diff --git a/Data/Coerce.hs b/Data/Coerce.hs
--- a/Data/Coerce.hs
+++ b/Data/Coerce.hs
@@ -21,6 +21,7 @@
 
 module Data.Coerce
         ( -- * Safe coercions
+          -- @since 4.7.0.0
           coerce, Coercible
         ) where
 import GHC.Prim (coerce)
diff --git a/GHC/Event/Thread.hs b/GHC/Event/Thread.hs
--- a/GHC/Event/Thread.hs
+++ b/GHC/Event/Thread.hs
@@ -18,7 +18,7 @@
 -- TODO: Use new Windows I/O manager
 import Control.Exception (finally, SomeException, toException)
 import Data.Foldable (forM_, mapM_, sequence_)
-import Data.IORef (IORef, newIORef, readIORef, writeIORef)
+import Data.IORef (IORef, newIORef, readIORef, writeIORef, atomicWriteIORef)
 import Data.Maybe (fromMaybe)
 import Data.Tuple (snd)
 import Foreign.C.Error (eBADF, errnoToIOError)
@@ -29,7 +29,8 @@
 import GHC.Conc.Sync (TVar, ThreadId, ThreadStatus(..), atomically, forkIO,
                       labelThread, modifyMVar_, withMVar, newTVar, sharedCAF,
                       getNumCapabilities, threadCapability, myThreadId, forkOn,
-                      threadStatus, writeTVar, newTVarIO, readTVar, retry,throwSTM,STM)
+                      threadStatus, writeTVar, newTVarIO, readTVar, retry,
+                      throwSTM, STM, yield)
 import GHC.IO (mask_, uninterruptibleMask_, onException)
 import GHC.IO.Exception (ioError)
 import GHC.IOArray (IOArray, newIOArray, readIOArray, writeIOArray,
@@ -41,6 +42,7 @@
                              new, registerFd, unregisterFd_)
 import qualified GHC.Event.Manager as M
 import qualified GHC.Event.TimerManager as TM
+import GHC.Ix (inRange)
 import GHC.Num ((-), (+))
 import GHC.Real (fromIntegral)
 import GHC.Show (showSignedInt)
@@ -98,23 +100,45 @@
 closeFdWith :: (Fd -> IO ())        -- ^ Action that performs the close.
             -> Fd                   -- ^ File descriptor to close.
             -> IO ()
-closeFdWith close fd = do
-  eventManagerArray <- readIORef eventManager
-  let (low, high) = boundsIOArray eventManagerArray
-  mgrs <- flip mapM [low..high] $ \i -> do
-    Just (_,!mgr) <- readIOArray eventManagerArray i
-    return mgr
-  -- 'takeMVar', and 'M.closeFd_' might block, although for a very short time.
-  -- To make 'closeFdWith' safe in presence of asynchronous exceptions we have
-  -- to use uninterruptible mask.
-  uninterruptibleMask_ $ do
-    tables <- flip mapM mgrs $ \mgr -> takeMVar $ M.callbackTableVar mgr fd
-    cbApps <- zipWithM (\mgr table -> M.closeFd_ mgr table fd) mgrs tables
-    close fd `finally` sequence_ (zipWith3 finish mgrs tables cbApps)
+closeFdWith close fd = close_loop
   where
     finish mgr table cbApp = putMVar (M.callbackTableVar mgr fd) table >> cbApp
     zipWithM f xs ys = sequence (zipWith f xs ys)
+      -- The array inside 'eventManager' can be swapped out at any time, see
+      -- 'ioManagerCapabilitiesChanged'. See #21651. We detect this case by
+      -- checking the array bounds before and after. When such a swap has
+      -- happened we cleanup and try again
+    close_loop = do
+      eventManagerArray <- readIORef eventManager
+      let ema_bounds@(low, high) = boundsIOArray eventManagerArray
+      mgrs <- flip mapM [low..high] $ \i -> do
+        Just (_,!mgr) <- readIOArray eventManagerArray i
+        return mgr
 
+      -- 'takeMVar', and 'M.closeFd_' might block, although for a very short time.
+      -- To make 'closeFdWith' safe in presence of asynchronous exceptions we have
+      -- to use uninterruptible mask.
+      join $ uninterruptibleMask_ $ do
+        tables <- flip mapM mgrs $ \mgr -> takeMVar $ M.callbackTableVar mgr fd
+        new_ema_bounds <- boundsIOArray `fmap` readIORef eventManager
+        -- Here we exploit Note [The eventManager Array]
+        if new_ema_bounds /= ema_bounds
+          then do
+            -- the array has been modified.
+            -- mgrs still holds the right EventManagers, by the Note.
+            -- new_ema_bounds must be larger than ema_bounds, by the note.
+            -- return the MVars we took and try again
+            sequence_ $ zipWith (\mgr table -> finish mgr table (pure ())) mgrs tables
+            pure close_loop
+          else do
+            -- We surely have taken all the appropriate MVars. Even if the array
+            -- has been swapped, our mgrs is still correct.
+            -- Remove the Fd from all callback tables, close the Fd, and run all
+            -- callbacks.
+            cbApps <- zipWithM (\mgr table -> M.closeFd_ mgr table fd) mgrs tables
+            close fd `finally` sequence_ (zipWith3 finish mgrs tables cbApps)
+            pure (pure ())
+
 threadWait :: Event -> Fd -> IO ()
 threadWait evt fd = mask_ $ do
   m <- newEmptyMVar
@@ -177,10 +201,24 @@
 getSystemEventManager :: IO (Maybe EventManager)
 getSystemEventManager = do
   t <- myThreadId
-  (cap, _) <- threadCapability t
   eventManagerArray <- readIORef eventManager
-  mmgr <- readIOArray eventManagerArray cap
-  return $ fmap snd mmgr
+  let r = boundsIOArray eventManagerArray
+  (cap, _) <- threadCapability t
+  -- It is possible that we've just increased the number of capabilities and the
+  -- new EventManager has not yet been constructed by
+  -- 'ioManagerCapabilitiesChanged'. We expect this to happen very rarely.
+  -- T21561 exercises this.
+  -- Two options to proceed:
+  --  1) return the EventManager for capability 0. This is guaranteed to exist,
+  --     and "shouldn't" cause any correctness issues.
+  --  2) Busy wait, with or without a call to 'yield'. This can't deadlock,
+  --     because we must be on a brand capability and there must be a call to
+  --     'ioManagerCapabilitiesChanged' pending.
+  --
+  -- We take the second option, with the yield, judging it the most robust.
+  if not (inRange r cap)
+    then yield >> getSystemEventManager
+    else fmap snd `fmap` readIOArray eventManagerArray cap
 
 getSystemEventManager_ :: IO EventManager
 getSystemEventManager_ = do
@@ -191,6 +229,22 @@
 foreign import ccall unsafe "getOrSetSystemEventThreadEventManagerStore"
     getOrSetSystemEventThreadEventManagerStore :: Ptr a -> IO (Ptr a)
 
+-- Note [The eventManager Array]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-- A mutable array holding the current EventManager for each capability
+-- An entry is Nothing only while the eventmanagers are initialised, see
+-- 'startIOManagerThread' and 'ioManagerCapabilitiesChanged'.
+-- The 'ThreadId' at array position 'cap'  will have been 'forkOn'ed capabality
+-- 'cap'.
+-- The array will be swapped with newer arrays when the number of capabilities
+-- changes(via 'setNumCapabilities'). However:
+--   * the size of the arrays will never decrease; and
+--   * The 'EventManager's in the array are not replaced with other
+--     'EventManager' constructors.
+--
+-- This is a similar strategy as the rts uses for it's
+-- capabilities array (n_capabilities is the size of the array,
+-- enabled_capabilities' is the number of active capabilities).
 eventManager :: IORef (IOArray Int (Maybe (ThreadId, EventManager)))
 eventManager = unsafePerformIO $ do
     numCaps <- getNumCapabilities
@@ -351,7 +405,9 @@
                 startIOManagerThread new_eventManagerArray
 
               -- update the event manager array reference:
-              writeIORef eventManager new_eventManagerArray
+              atomicWriteIORef eventManager new_eventManagerArray
+              -- We need an atomic write here because 'eventManager' is accessed
+              -- unsynchronized in 'getSystemEventManager' and 'closeFdWith'
       else when (new_n_caps > numEnabled) $
             forM_ [numEnabled..new_n_caps-1] $ \i -> do
               Just (_,mgr) <- readIOArray eventManagerArray i
diff --git a/GHC/Exts.hs b/GHC/Exts.hs
--- a/GHC/Exts.hs
+++ b/GHC/Exts.hs
@@ -120,6 +120,8 @@
         unsafeCoerce#,
 
         -- ** Casting class dictionaries with single methods
+        --
+        --   @since 4.17.0.0
         WithDict(..),
 
         -- * The maximum tuple size
diff --git a/GHC/Float.hs b/GHC/Float.hs
--- a/GHC/Float.hs
+++ b/GHC/Float.hs
@@ -1541,7 +1541,7 @@
 -- | @'castWord32ToFloat' w@ does a bit-for-bit copy from an integral value
 -- to a floating-point value.
 --
--- @since 4.10.0.0
+-- @since 4.11.0.0
 
 {-# INLINE castWord32ToFloat #-}
 castWord32ToFloat :: Word32 -> Float
@@ -1554,7 +1554,7 @@
 -- | @'castFloatToWord32' f@ does a bit-for-bit copy from a floating-point value
 -- to an integral value.
 --
--- @since 4.10.0.0
+-- @since 4.11.0.0
 
 {-# INLINE castFloatToWord32 #-}
 castFloatToWord32 :: Float -> Word32
@@ -1568,7 +1568,7 @@
 -- | @'castWord64ToDouble' w@ does a bit-for-bit copy from an integral value
 -- to a floating-point value.
 --
--- @since 4.10.0.0
+-- @since 4.11.0.0
 
 {-# INLINE castWord64ToDouble #-}
 castWord64ToDouble :: Word64 -> Double
@@ -1581,7 +1581,7 @@
 -- | @'castFloatToWord64' f@ does a bit-for-bit copy from a floating-point value
 -- to an integral value.
 --
--- @since 4.10.0.0
+-- @since 4.11.0.0
 
 {-# INLINE castDoubleToWord64 #-}
 castDoubleToWord64 :: Double -> Word64
diff --git a/GHC/IO/Windows/Handle.hsc b/GHC/IO/Windows/Handle.hsc
--- a/GHC/IO/Windows/Handle.hsc
+++ b/GHC/IO/Windows/Handle.hsc
@@ -576,24 +576,23 @@
 
 consoleRead :: Bool -> Io ConsoleHandle -> Ptr Word8 -> Word64 -> Int -> IO Int
 consoleRead blocking hwnd ptr _offset bytes
-  = withUTF16ToGhcInternal ptr bytes $ \reqBytes w_ptr ->
-      alloca $ \res -> do
-       cooked <- isCooked hwnd
-       -- Cooked input must be handled differently when the STD handles are
-       -- attached to a real console handle.  For File based handles we can't do
-       -- proper cooked inputs, but since the actions are async you would get
-       -- results as soon as available.
-       --
-       -- For console handles We have to use a lower level API then ReadConsole,
-       -- namely we must use ReadConsoleInput which requires us to process
-       -- all console message manually.
-       --
-       -- Do note that MSYS2 shells such as bash don't attach to a real handle,
-       -- and instead have by default a pipe/file based std handles.  Which
-       -- means the cooked behaviour is best when used in a native Windows
-       -- terminal such as cmd, powershell or ConEmu.
-       case cooked || not blocking of
-        False -> do
+  = alloca $ \res -> do
+      cooked <- isCooked hwnd
+      -- Cooked input must be handled differently when the STD handles are
+      -- attached to a real console handle.  For File based handles we can't do
+      -- proper cooked inputs, but since the actions are async you would get
+      -- results as soon as available.
+      --
+      -- For console handles We have to use a lower level API then ReadConsole,
+      -- namely we must use ReadConsoleInput which requires us to process
+      -- all console message manually.
+      --
+      -- Do note that MSYS2 shells such as bash don't attach to a real handle,
+      -- and instead have by default a pipe/file based std handles.  Which
+      -- means the cooked behaviour is best when used in a native Windows
+      -- terminal such as cmd, powershell or ConEmu.
+      case cooked || not blocking of
+        False -> withUTF16ToGhcInternal ptr bytes $ \reqBytes w_ptr ->  do
           debugIO "consoleRead :: un-cooked I/O read."
           -- eotControl allows us to handle control characters like EOL
           -- without needing a newline, which would sort of defeat the point
@@ -628,9 +627,9 @@
           -- characters as they are.  Technically this function can handle any
           -- console event.  Including mouse, window and virtual key events
           -- but for now I'm only interested in key presses.
-          let entries = fromIntegral $ reqBytes `div` (#size INPUT_RECORD)
+          let entries = fromIntegral $ bytes `div` (#size INPUT_RECORD)
           allocaBytes entries $ \p_inputs ->
-            maybeReadEvent p_inputs entries res w_ptr
+            maybeReadEvent p_inputs entries res ptr
 
           -- Check to see if we have been explicitly asked to do a non-blocking
           -- I/O, and if we were, make sure that if we didn't have any console
@@ -657,6 +656,7 @@
 
             b_read <- fromIntegral <$> peek res
             read <- cobble b_read w_ptr p_inputs
+            debugIO $ "readEvent: =" ++ show read
             if read > 0
                then return $ fromIntegral read
                else maybeReadEvent p_inputs entries res w_ptr
@@ -665,7 +665,7 @@
           -- minimum required to know which key/sequences were pressed.  To do
           -- this and prevent having to fully port the PINPUT_RECORD structure
           -- in Haskell we use some GCC builtins to find the correct offsets.
-          cobble :: Int -> Ptr Word16 -> PINPUT_RECORD -> IO Int
+          cobble :: Int -> Ptr Word8 -> PINPUT_RECORD -> IO Int
           cobble 0 _ _ = do debugIO "cobble: done."
                             return 0
           cobble n w_ptr p_inputs =
@@ -690,8 +690,18 @@
                           debugIO $ "cobble: offset - " ++ show char_offset
                           debugIO $ "cobble: show > " ++ show char
                           debugIO $ "cobble: repeat: " ++ show repeated
+                          -- The documentation here is rather subtle, but
+                          -- according to MSDN the uWChar being provided here
+                          -- has been "translated".  What this actually means
+                          -- is that the surrogate pairs have already been
+                          -- translated into byte sequences.  That is, despite
+                          -- the Word16 storage type, it's actually a byte
+                          -- stream.  This means we shouldn't try to decode
+                          -- to UTF-8 again since we'd end up incorrectly
+                          -- interpreting two bytes as an extended unicode
+                          -- character.
                           pokeArray w_ptr $ replicate repeated char
-                          (+1) <$> cobble n' w_ptr' p_inputs'
+                          (+repeated) <$> cobble n' w_ptr' p_inputs'
                   else do debugIO $ "cobble: skip event."
                           cobble n' w_ptr p_inputs'
 
diff --git a/System/Posix/Internals.hs b/System/Posix/Internals.hs
--- a/System/Posix/Internals.hs
+++ b/System/Posix/Internals.hs
@@ -430,98 +430,113 @@
 foreign import ccall unsafe "HsBase.h __hscore_lstat"
    lstat :: CFilePath -> Ptr CStat -> IO CInt
 
-{- Note: Win32 POSIX functions
-Functions that are not part of the POSIX standards were
-at some point deprecated by Microsoft. This deprecation
-was performed by renaming the functions according to the
-C++ ABI Section 17.6.4.3.2b. This was done to free up the
-namespace of normal Windows programs since Windows isn't
-POSIX compliant anyway.
+#if defined(mingw32_HOST_OS)
+-- See Note [Windows types]
+foreign import capi unsafe "HsBase.h _read"
+   c_read :: CInt -> Ptr Word8 -> CUInt -> IO CInt
 
-These were working before since the RTS was re-exporting
-these symbols under the undeprecated names. This is no longer
-being done. See #11223
+-- See Note [Windows types]
+foreign import capi safe "HsBase.h _read"
+   c_safe_read :: CInt -> Ptr Word8 -> CUInt -> IO CInt
 
-See https://msdn.microsoft.com/en-us/library/ms235384.aspx
-for more.
+foreign import ccall unsafe "HsBase.h _umask"
+   c_umask :: CMode -> IO CMode
 
-However since we can't hope to get people to support Windows
-packages we should support the deprecated names. See #12497
--}
-foreign import capi unsafe "unistd.h lseek"
-   c_lseek :: CInt -> COff -> CInt -> IO COff
+-- See Note [Windows types]
+foreign import capi unsafe "HsBase.h _write"
+   c_write :: CInt -> Ptr Word8 -> CUInt -> IO CInt
 
-foreign import ccall unsafe "HsBase.h access"
+-- See Note [Windows types]
+foreign import capi safe "HsBase.h _write"
+   c_safe_write :: CInt -> Ptr Word8 -> CUInt -> IO CInt
+
+foreign import ccall unsafe "HsBase.h _pipe"
+   c_pipe :: Ptr CInt -> IO CInt
+
+foreign import capi unsafe "HsBase.h _lseeki64"
+   c_lseek :: CInt -> Int64 -> CInt -> IO Int64
+
+foreign import capi unsafe "HsBase.h _access"
    c_access :: CString -> CInt -> IO CInt
 
-foreign import ccall unsafe "HsBase.h chmod"
+foreign import ccall unsafe "HsBase.h _chmod"
    c_chmod :: CString -> CMode -> IO CInt
 
-foreign import ccall unsafe "HsBase.h close"
+foreign import capi unsafe "HsBase.h _close"
    c_close :: CInt -> IO CInt
 
-foreign import ccall unsafe "HsBase.h creat"
+foreign import capi unsafe "HsBase.h _creat"
    c_creat :: CString -> CMode -> IO CInt
 
-foreign import ccall unsafe "HsBase.h dup"
+foreign import ccall unsafe "HsBase.h _dup"
    c_dup :: CInt -> IO CInt
 
-foreign import ccall unsafe "HsBase.h dup2"
+foreign import ccall unsafe "HsBase.h _dup2"
    c_dup2 :: CInt -> CInt -> IO CInt
 
-foreign import ccall unsafe "HsBase.h isatty"
+foreign import capi unsafe "HsBase.h _isatty"
    c_isatty :: CInt -> IO CInt
 
-#if defined(mingw32_HOST_OS)
--- See Note: Windows types
-foreign import capi unsafe "HsBase.h _read"
-   c_read :: CInt -> Ptr Word8 -> CUInt -> IO CInt
-
--- See Note: Windows types
-foreign import capi safe "HsBase.h _read"
-   c_safe_read :: CInt -> Ptr Word8 -> CUInt -> IO CInt
-
-foreign import ccall unsafe "HsBase.h _umask"
-   c_umask :: CMode -> IO CMode
+foreign import capi unsafe "HsBase.h _unlink"
+   c_unlink :: CString -> IO CInt
 
--- See Note: Windows types
-foreign import capi unsafe "HsBase.h _write"
-   c_write :: CInt -> Ptr Word8 -> CUInt -> IO CInt
+foreign import capi unsafe "HsBase.h _utime"
+   c_utime :: CString -> Ptr CUtimbuf -> IO CInt
 
--- See Note: Windows types
-foreign import capi safe "HsBase.h _write"
-   c_safe_write :: CInt -> Ptr Word8 -> CUInt -> IO CInt
+foreign import capi unsafe "HsBase.h _getpid"
+   c_getpid :: IO CPid
 
-foreign import ccall unsafe "HsBase.h _pipe"
-   c_pipe :: Ptr CInt -> IO CInt
 #else
 -- We use CAPI as on some OSs (eg. Linux) this is wrapped by a macro
 -- which redirects to the 64-bit-off_t versions when large file
 -- support is enabled.
 
--- See Note: Windows types
+-- See Note [Windows types]
 foreign import capi unsafe "HsBase.h read"
    c_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
 
--- See Note: Windows types
+-- See Note [Windows types]
 foreign import capi safe "HsBase.h read"
    c_safe_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
 
 foreign import ccall unsafe "HsBase.h umask"
    c_umask :: CMode -> IO CMode
 
--- See Note: Windows types
+-- See Note [Windows types]
 foreign import capi unsafe "HsBase.h write"
    c_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
 
--- See Note: Windows types
+-- See Note [Windows types]
 foreign import capi safe "HsBase.h write"
    c_safe_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
 
 foreign import ccall unsafe "HsBase.h pipe"
    c_pipe :: Ptr CInt -> IO CInt
-#endif
 
+foreign import capi unsafe "unistd.h lseek"
+   c_lseek :: CInt -> COff -> CInt -> IO COff
+
+foreign import ccall unsafe "HsBase.h access"
+   c_access :: CString -> CInt -> IO CInt
+
+foreign import ccall unsafe "HsBase.h chmod"
+   c_chmod :: CString -> CMode -> IO CInt
+
+foreign import ccall unsafe "HsBase.h close"
+   c_close :: CInt -> IO CInt
+
+foreign import ccall unsafe "HsBase.h creat"
+   c_creat :: CString -> CMode -> IO CInt
+
+foreign import ccall unsafe "HsBase.h dup"
+   c_dup :: CInt -> IO CInt
+
+foreign import ccall unsafe "HsBase.h dup2"
+   c_dup2 :: CInt -> CInt -> IO CInt
+
+foreign import ccall unsafe "HsBase.h isatty"
+   c_isatty :: CInt -> IO CInt
+
 foreign import ccall unsafe "HsBase.h unlink"
    c_unlink :: CString -> IO CInt
 
@@ -530,6 +545,7 @@
 
 foreign import ccall unsafe "HsBase.h getpid"
    c_getpid :: IO CPid
+#endif
 
 foreign import ccall unsafe "HsBase.h __hscore_stat"
    c_stat :: CFilePath -> Ptr CStat -> IO CInt
@@ -656,7 +672,8 @@
 foreign import capi  unsafe "stdio.h value SEEK_END" sEEK_END :: CInt
 
 {-
-Note: Windows types
+Note [Windows types]
+~~~~~~~~~~~~~~~~~~~~
 
 Windows' _read and _write have types that differ from POSIX. They take an
 unsigned int for length and return a signed int where POSIX uses size_t and
diff --git a/base.cabal b/base.cabal
--- a/base.cabal
+++ b/base.cabal
@@ -1,6 +1,6 @@
 cabal-version:  3.0
 name:           base
-version:        4.17.0.0
+version:        4.17.1.0
 -- NOTE: Don't forget to update ./changelog.md
 
 license:        BSD-3-Clause
@@ -377,7 +377,6 @@
     if os(windows)
         -- Windows requires some extra libraries for linking because the RTS
         -- is no longer re-exporting them.
-        -- mingwex: provides C99 compatibility. libm is a stub on MingW.
         -- mingw32: Unfortunately required because of a resource leak between
         --          mingwex and mingw32. the __math_err symbol is defined in
         --          mingw32 which is required by mingwex.
@@ -390,7 +389,7 @@
         -- advapi32: provides advanced kernel functions
         extra-libraries:
             wsock32, user32, shell32, mingw32, kernel32, advapi32,
-            mingwex, ws2_32, shlwapi, ole32, rpcrt4, ntdll
+            ws2_32, shlwapi, ole32, rpcrt4, ntdll
         -- Minimum supported Windows version.
         -- These numbers can be found at:
         --  https://msdn.microsoft.com/en-us/library/windows/desktop/aa383745(v=vs.85).aspx
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,11 @@
 # Changelog for [`base` package](http://hackage.haskell.org/package/base)
 
+## 4.17.1.0 *April 2023*
+
+   * Remove `mingwex` dependency on Windows (#22166).
+
+   * Fix inconsistency with decoding terminal input on Windows (#21488).
+
 ## 4.17.0.0 *August 2022*
 
   * Add explicitly bidirectional `pattern TypeRep` to `Type.Reflection`.
@@ -77,7 +83,26 @@
     `Word64#` and `Int64#`, respectively. Previously on 32-bit platforms these
     were rather represented by `Word#` and `Int#`. See GHC #11953.
 
+  * Add `GHC.TypeError` module to contain functionality related to custom type
+    errors. `TypeError` is re-exported from `GHC.TypeLits` for backwards
+    compatibility.
 
+## 4.16.3.0 *May 2022*
+
+  * Shipped with GHC 9.2.4
+
+  * winio: make consoleReadNonBlocking not wait for any events at all.
+
+  * winio: Add support to console handles to handleToHANDLE
+
+## 4.16.2.0 *May 2022*
+
+  * Shipped with GHC 9.2.2
+
+  * Export GHC.Event.Internal on Windows (#21245)
+
+  # Documentation Fixes
+
 ## 4.16.1.0 *Feb 2022*
 
   * Shipped with GHC 9.2.2
@@ -138,10 +163,6 @@
 
   * `fromInteger :: Integer -> Float/Double` now consistently round to the
     nearest value, with ties to even.
-
-  * Add `GHC.TypeError` module to contain functionality related to custom type
-    errors. `TypeError` is re-exported from `GHC.TypeLits` for backwards
-    compatibility.
 
   * Comparison constraints in `Data.Type.Ord` (e.g. `<=`) now use the new
     `GHC.TypeError.Assert` type family instead of type equality with `~`.
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -3997,7 +3997,7 @@
 fi
 done
 
-for ac_func in _chsize ftruncate
+for ac_func in _chsize_s ftruncate
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -38,7 +38,7 @@
 AC_CHECK_LIB([rt], [clock_gettime])
 AC_CHECK_FUNCS([clock_gettime])
 AC_CHECK_FUNCS([getclock getrusage times])
-AC_CHECK_FUNCS([_chsize ftruncate])
+AC_CHECK_FUNCS([_chsize_s ftruncate])
 
 # event-related fun
 # The line below already defines HAVE_KQUEUE and HAVE_POLL, so technically some of the
diff --git a/include/HsBase.h b/include/HsBase.h
--- a/include/HsBase.h
+++ b/include/HsBase.h
@@ -283,15 +283,12 @@
 INLINE int
 __hscore_ftruncate( int fd, off_t where )
 {
-#if defined(HAVE_FTRUNCATE)
+#if defined(HAVE__CHSIZE_S)
+  return _chsize_s(fd,where);
+#elif defined(HAVE_FTRUNCATE)
   return ftruncate(fd,where);
-#elif defined(HAVE__CHSIZE)
-  return _chsize(fd,where);
 #else
-// ToDo: we should use _chsize_s() on Windows which allows a 64-bit
-// offset, but it doesn't seem to be available from mingw at this time
-// --SDM (01/2008)
-#error at least ftruncate or _chsize functions are required to build
+#error at least _chsize_s or ftruncate functions are required to build
 #endif
 }
 
diff --git a/include/HsBaseConfig.h.in b/include/HsBaseConfig.h.in
--- a/include/HsBaseConfig.h.in
+++ b/include/HsBaseConfig.h.in
@@ -478,8 +478,8 @@
 /* Define to 1 if you have the <winsock.h> header file. */
 #undef HAVE_WINSOCK_H
 
-/* Define to 1 if you have the `_chsize' function. */
-#undef HAVE__CHSIZE
+/* Define to 1 if you have the `_chsize_s' function. */
+#undef HAVE__CHSIZE_S
 
 /* Define to Haskell type for blkcnt_t */
 #undef HTYPE_BLKCNT_T
