diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,19 @@
-# Revision history for ping
+# Changelog
+All notable changes to this project will be documented in this file.
 
-## 0.1.0.0 -- YYYY-mm-dd
+The format is inspired by [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
+This changelog deviates from the recommendation by not grouping changes into
+added, changed, deprecated, etc. subsections.
 
-* First version. Released on an unsuspecting world.
+This project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/).
+
+## [0.1.0.1] - 2018-01-07
+- Fix a problem in `multihosts` that occassionally caused the function
+  to wait for a number of nanoseconds close to `maxBound :: Word64`.
+  This had been caused by a subtraction underflow.
+
+## [0.1.0.0] - 2018-01-02
+- Initial release.
+- Function `host` for pinging a single host once.
+- Function `hosts` and `range` for pinging multiple hosts once each.
+- Function `multihosts` and `multirange` for pinging multiple hosts once each.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,45 @@
+# ping
+
+## Objective
+
+This library provides high-performance functions that issue ICMP echo
+requests and wait for responses, measuring the elapsed time. It is intended
+to be cross-platform as possible, and it may use any system APIs available.
+However, it will not resort to running `/bin/ping` as a subprocess. Pull
+requests that improve compatibility will accepted so long as they do not
+start a subprocess.
+
+## Build Instructions
+
+This library relies on `posix-api`, which needs a currently-unreleased
+version of `hsc2hs` in order to build. In order to try out this library, try:
+
+```
+~/dev $ git clone https://github.com/haskell/hsc2hs
+~/dev $ cd hsc2hs
+~/dev/hsc2hs $ cabal install
+~/dev/hsc2hs $ cd ..
+~/dev $ git clone https://github.com/andrewthad/ping
+~/dev $ cd ping
+~/dev/ping $ cabal new-build --with-hsc2hs=~/.cabal/bin/hsc2hs
+```
+
+This will build all dependencies, including `posix-api`, with the
+upstream `hsc2hs` tool.
+
+## Infelicities
+
+This project's objective is to be cross-platform. However, it does not
+accomplish this. The author primarily runs a Debian Linux distribution
+and consequently lacks the resources and the motivation to make this
+work on other platforms. Contributions to improve compatibility are
+welcomed. Current known problems include:
+
+- On Linux, the library should fallback to using raw sockets if `IPPROTO_ICMP`
+  does not work.
+- Support for Windows is missing.
+- Support for BSD is missing. However, adding raw socket support to improve
+  the situation on Linux may fix this as well.
+- Support for Darwin is missing. This should not be difficult since
+  Darwin supports `IPPROTO_ICMP` sockets.
+
diff --git a/ping.cabal b/ping.cabal
--- a/ping.cabal
+++ b/ping.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.2
 name: ping
-version: 0.1.0.1
+version: 0.1.0.2
 synopsis: icmp echo requests
 description:
   This library provides functions that have similar behavior as the
@@ -23,11 +23,12 @@
 license-file: LICENSE
 author: Andrew Martin
 maintainer: andrew.thaddeus@gmail.com
-copyright: 2018 Andrew Martin
+copyright: 2019 Andrew Martin
 category: Network
 build-type: Simple
 extra-source-files:
   CHANGELOG.md
+  README.md
   include/custom.h
 
 flag debug
@@ -45,7 +46,7 @@
     , base >= 4.11.1 && <5
     , ip >= 1.4
     , cpu >= 0.1.2
-    , posix-api >= 0.1
+    , posix-api >= 0.2.1 && < 0.3
     , primitive >= 0.6.4
     , primitive-containers >= 0.3.1
     , stm >= 2.5
diff --git a/src/Network/Icmp/Ping/Hosts.hs b/src/Network/Icmp/Ping/Hosts.hs
--- a/src/Network/Icmp/Ping/Hosts.hs
+++ b/src/Network/Icmp/Ping/Hosts.hs
@@ -120,7 +120,7 @@
   -> SU.Set IPv4 -- ^ Hosts
   -> IO (Either IcmpException (MUU.Map IPv4 Word64)) -- ^ Elapsed nanoseconds for responding hosts
 hosts !pause !theHosts = do
-  mask $ \restore -> SCK.socket SCK.internet SCK.datagram SCK.icmp >>= \case
+  mask $ \restore -> SCK.uninterruptibleSocket SCK.internet SCK.datagram SCK.icmp >>= \case
     Left (Errno e) -> pure (Left (IcmpExceptionSocket e))
     Right sock -> do
       durations <- restore
@@ -140,8 +140,8 @@
                  )
         )
         `onException`
-        (SCK.unsafeClose sock)
-      SCK.unsafeClose sock >>= \case
+        (SCK.uninterruptibleClose sock)
+      SCK.uninterruptibleClose sock >>= \case
         Left (Errno e) -> pure (Left (IcmpExceptionClose e))
         Right _ -> pure durations
 
@@ -153,7 +153,7 @@
       waitForReadWrite sock >>= \case
         True -> do
           debug "ready for read"
-          r <- SCK.unsafeReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait
+          r <- SCK.uninterruptibleReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait
           case r of
             Left (Errno e) -> pure (Left (IcmpExceptionReceive e))
             Right receivedBytes -> if receivedBytes == intToCSize fullPacketSize
@@ -185,7 +185,7 @@
           pokeIcmpHeader buffer (intToWord16 ix) (getIPv4 host)
           let sockaddr = SCK.encodeSocketAddressInternet
                 (SocketAddressInternet { port = 0, address = toBE32 (getIPv4 host) })
-          mwriteError <- SCK.unsafeSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr
+          mwriteError <- SCK.uninterruptibleSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr
           case mwriteError of
             Left (Errno e)
                 -- When you try to send a packet to a broadcast address, the kernel
@@ -221,7 +221,7 @@
         isReady <- waitForRead remainingMicroseconds sock
         if isReady
           then do
-            r <- SCK.unsafeReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait
+            r <- SCK.uninterruptibleReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait
             case r of
               Left (Errno e) -> pure (Left (IcmpExceptionReceive e))
               Right receivedBytes -> if receivedBytes == intToCSize fullPacketSize
diff --git a/src/Network/Icmp/Ping/Multihosts.hs b/src/Network/Icmp/Ping/Multihosts.hs
--- a/src/Network/Icmp/Ping/Multihosts.hs
+++ b/src/Network/Icmp/Ping/Multihosts.hs
@@ -121,7 +121,7 @@
 -- over the course of the loop's execution.
 multihosts !pause !successPause' !totalPings !cutoff !theHosts
   | pause <= 0 || totalPings <= 0 || cutoff <= 0 || SU.null theHosts = pure (Right mempty)
-  | otherwise = let !successPause = max successPause' 0 in mask $ \restore -> SCK.socket SCK.internet SCK.datagram SCK.icmp >>= \case
+  | otherwise = let !successPause = max successPause' 0 in mask $ \restore -> SCK.uninterruptibleSocket SCK.internet SCK.datagram SCK.icmp >>= \case
       Left (Errno e) -> pure (Left (IcmpExceptionSocket e))
       Right sock -> do
         !now0 <- getMonotonicTimeNSec
@@ -155,7 +155,7 @@
                          waitForRead shouldRead (word64ToInt microPause) sock >>= \case
                            True -> do
                              debug "Receiving in poll loop"
-                             r <- SCK.unsafeReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait
+                             r <- SCK.uninterruptibleReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait
                              case r of
                                Left (Errno e) -> pure (Left (IcmpExceptionReceive e))
                                Right receivedBytes -> if receivedBytes == intToCSize fullPacketSize
@@ -210,8 +210,8 @@
                        )
           )
           `onException`
-          (SCK.unsafeClose sock)
-        SCK.unsafeClose sock >>= \case
+          (SCK.uninterruptibleClose sock)
+        SCK.uninterruptibleClose sock >>= \case
           Left (Errno e) -> pure (Left (IcmpExceptionClose e))
           Right _ -> pure durations
 
@@ -269,7 +269,7 @@
   let sockaddr = SCK.encodeSocketAddressInternet
         (SocketAddressInternet { port = 0, address = toBE32 (getIPv4 theHost) })
   mwriteError <- writeWhenReady
-    (SCK.unsafeSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr)
+    (SCK.uninterruptibleSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr)
     (threadWaitWrite sock)
   case mwriteError of
     Left (Errno e)
diff --git a/src/Network/Icmp/Ping/Single.hs b/src/Network/Icmp/Ping/Single.hs
--- a/src/Network/Icmp/Ping/Single.hs
+++ b/src/Network/Icmp/Ping/Single.hs
@@ -49,7 +49,7 @@
     -- has a fancy way to display the failure. The user will likely need to
     -- rerun the program with CAP_NET_RAW or as root or after adjusting
     -- net.ipv4.ping_group_range with sysctl.
-    mask $ \restore -> SCK.socket SCK.internet SCK.datagram SCK.icmp >>= \case
+    mask $ \restore -> SCK.uninterruptibleSocket SCK.internet SCK.datagram SCK.icmp >>= \case
       Left (Errno e) -> pure (Left (IcmpExceptionSocket e))
       Right sock -> do
         elapsed <- restore
@@ -61,7 +61,7 @@
                pokeIcmpHeader buffer 0 w 
                start <- getMonotonicTimeNSec
                mwriteError <- writeWhenReady
-                 (SCK.unsafeSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr)
+                 (SCK.uninterruptibleSendToMutableByteArray sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait sockaddr)
                  (threadWaitWrite sock)
                case mwriteError of
                  Left (Errno e)
@@ -75,7 +75,7 @@
                        isReady <- waitForRead maxWaitTime sock
                        if isReady
                          then do
-                           r <- SCK.unsafeReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait
+                           r <- SCK.uninterruptibleReceiveFromMutableByteArray_ sock buffer 0 (intToCSize fullPacketSize) SCK.dontWait
                            case r of
                              Left (Errno e) -> pure (Left (IcmpExceptionReceive e))
                              Right receivedBytes -> if receivedBytes == intToCSize fullPacketSize
@@ -98,10 +98,10 @@
           -- by unsafeClose (not that we expect to see any). We do this
           -- because there is no other sensible behavior. We would much
           -- rather preserve the original exception.
-          (SCK.unsafeClose sock)
+          (SCK.uninterruptibleClose sock)
         -- It is not neccessary to use closeFdWith here since the socket
         -- cannot possibly be seen by more than one thread.
-        SCK.unsafeClose sock >>= \case
+        SCK.uninterruptibleClose sock >>= \case
           Left (Errno e) -> pure (Left (IcmpExceptionClose e))
           Right _ -> pure elapsed
 
