+
+It is useful to think of 'mask' not as a way to completely prevent
+asynchronous exceptions, but as a filter that allows them to be raised
+only at certain places. The main difficulty with asynchronous
+exceptions is that they normally can occur anywhere, but within a
+'mask' an asynchronous exception is only raised by operations that are
+interruptible (or call other interruptible operations). In many cases
+these operations may themselves raise exceptions, such as I\/O errors,
+so the caller should be prepared to handle exceptions arising from the
+operation anyway.
+
+Sometimes it is too onerous to handle exceptions in the middle of a
+critical piece of stateful code. There are three ways to handle this
+kind of situation:
+
+ * Use STM. Since a transaction is always either completely executed
+ or not at all, transactions are a good way to maintain invariants
+ over state in the presence of asynchronous (and indeed synchronous)
+ exceptions.
+
+ * Use 'mask', and avoid interruptible operations. In order to do
+ this, we have to know which operations are interruptible. It is
+ impossible to know for any given library function whether it might
+ invoke an interruptible operation internally; so instead we give a
+ list of guaranteed-not-to-be-interruptible operations below.
+
+ * Use 'uninterruptibleMask'. This is generally not recommended,
+ unless you can guarantee that any interruptible operations invoked
+ during the scope of 'uninterruptibleMask' can only ever block for
+ a short time. Otherwise, 'uninterruptibleMask' is a good way to
+ make your program deadlock and be unresponsive to user interrupts.
+
+The following operations are guaranteed not to be interruptible:
+
+ * operations on 'IORef' from "Data.IORef"
+ * STM transactions that do not use 'retry'
+ * everything from the @Foreign@ modules
+ * everything from @Control.Exception@
+ * @tryTakeMVar@, @tryPutMVar@, @isEmptyMVar@
+ * @takeMVar@ if the @MVar@ is definitely full, and conversely @putMVar@ if the @MVar@ is definitely empty
+ * @newEmptyMVar@, @newMVar@
+ * @forkIO@, @forkIOUnmasked@, @myThreadId@
+
+-}
+
+{- $catchall
+
+It is possible to catch all exceptions, by using the type 'SomeException':
+
+> catch f (\e -> ... (e :: SomeException) ...)
+
+HOWEVER, this is normally not what you want to do!
+
+For example, suppose you want to read a file, but if it doesn't exist
+then continue as if it contained \"\". You might be tempted to just
+catch all exceptions and return \"\" in the handler. However, this has
+all sorts of undesirable consequences. For example, if the user
+presses control-C at just the right moment then the 'UserInterrupt'
+exception will be caught, and the program will continue running under
+the belief that the file contains \"\". Similarly, if another thread
+tries to kill the thread reading the file then the 'ThreadKilled'
+exception will be ignored.
+
+Instead, you should only catch exactly the exceptions that you really
+want. In this case, this would likely be more specific than even
+\"any IO exception\"; a permissions error would likely also want to be
+handled differently. Instead, you would probably want something like:
+
+> e <- tryJust (guard . isDoesNotExistError) (readFile f)
+> let str = either (const "") id e
+
+There are occassions when you really do need to catch any sort of
+exception. However, in most cases this is just so you can do some
+cleaning up; you aren't actually interested in the exception itself.
+For example, if you open a file then you want to close it again,
+whether processing the file executes normally or throws an exception.
+However, in these cases you can use functions like 'bracket', 'finally'
+and 'onException', which never actually pass you the exception, but
+just call the cleanup functions at the appropriate points.
+
+But sometimes you really do need to catch any exception, and actually
+see what the exception is. One example is at the very top-level of a
+program, you may wish to catch any exception, print it to a logfile or
+the screen, and then exit gracefully. For these cases, you can use
+'catch' (or one of the other exception-catching functions) with the
+'SomeException' type.