diff --git a/docs/exception_handling/index.rst b/docs/exception_handling/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..0ea44485de00ec71f520c6b1753d9fff1abf5a21
--- /dev/null
+++ b/docs/exception_handling/index.rst
@@ -0,0 +1,13 @@
+Exception handling
+==================
+
+Satella provides a rich functionality to register exception hooks.
+
+Writing your own exception handlers
+-----------------------------------
+
+To write your own exception handlers, subclass the following class:
+
+.. autoclass:: satella.exception_handling.BaseExceptionHandler
+    :members:
+
diff --git a/docs/index.rst b/docs/index.rst
index bea568620e6a1a322e7845644b4fb1734e2aef5f..30e19e9e83f6480dc5c1f426a4f2c042151e6e0e 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -14,6 +14,7 @@ Welcome to satella's documentation!
            coding/concurrent
            instrumentation/traceback
            instrumentation/metrics
+           exception_handling/index
            json
            posix
            recipes
diff --git a/satella/posix/__init__.py b/satella/posix/__init__.py
index 183ac7e0997ed5d48372fbcedfa97fae927fc77d..88c5ed0588ee0f66d3ec4a5dd168f1895194155c 100644
--- a/satella/posix/__init__.py
+++ b/satella/posix/__init__.py
@@ -1,17 +1,13 @@
-# coding=UTF-8
 """
-UNIX things
+POSIX things
 """
-from __future__ import print_function, absolute_import, division
 
-import logging
 import os
 
 from .daemon import daemonize
 from .pidlock import AcquirePIDLock
 from .signals import hang_until_sig
 
-logger = logging.getLogger(__name__)
 
 __all__ = [
     'daemonize',
@@ -27,6 +23,7 @@ def is_running_as_root():
     Is this process running as root?
 
     Checks whether EUID is 0
+
     :return: bool
     """
     return os.geteuid() == 0
diff --git a/satella/posix/daemon.py b/satella/posix/daemon.py
index 73615c4222d8d213366489cc279dfba833a7ab74..69d81a023390d2515c31d83597e59e23bc014588 100644
--- a/satella/posix/daemon.py
+++ b/satella/posix/daemon.py
@@ -20,6 +20,9 @@ logger = logging.getLogger(__name__)
 DEVNULL = '/dev/null'
 
 
+__all__ = ['daemonize']
+
+
 def daemonize(exit_via: tp.Callable = sys.exit,
               redirect_std_to_devnull: bool = True,
               uid: tp.Optional[int] = None,
@@ -58,10 +61,10 @@ def daemonize(exit_via: tp.Callable = sys.exit,
     _parse_ug(gid, grp, 'gr_gid', os.setegid)
 
 
-def _parse_ug(no, module, fieldname, osfun):
+def _parse_ug(no, module, field_name, osfun):
     if no is not None:
         if isinstance(no, str):
-            no = getattr(module.getpwnam(no), fieldname)
+            no = getattr(module.getpwnam(no), field_name)
         osfun(no)
 
 
diff --git a/satella/posix/pidlock.py b/satella/posix/pidlock.py
index ef920b077dab4a77c1d4ae0526269d0f8242ac7b..30ded11ad61c59c27fedd3dba35d5229c6a2fefe 100644
--- a/satella/posix/pidlock.py
+++ b/satella/posix/pidlock.py
@@ -24,13 +24,17 @@ class AcquirePIDLock:
 
     Usage:
 
-        with AcquirePIDLock('myservice.pid'):
+    >>> with AcquirePIDLock('myservice.pid'):
+    >>>     ... rest of code ..
 
-            .. rest of code ..
+    Or alternatively
 
-    Exiting the context manager deletes the file.
+    >>> pid_lock = AcquirePIDLock('myservice.pid')
+    >>> pid_lock.acquire()
+    >>> ...
+    >>> pid_lock.release()
 
-    The constructor doesn't throw, __enter__ does, one of:
+    The constructor doesn't throw, __enter__ or acquire() does, one of:
 
     * AcquirePIDLock.FailedToAcquire - base class for errors. Thrown if can't read the file
     * AcquirePIDLock.LockIsHeld - lock is already held. This has two attributes - pid (int), the PID of holder,
@@ -55,8 +59,18 @@ class AcquirePIDLock:
 
         self.fileno = None
 
-    def _acquire(self):
-        """The mechanical process of acquisition"""
+    def release(self):
+        if self.fileno is not None:
+            os.close(self.fileno)
+            os.unlink(self.path)
+
+    def acquire(self):
+        """
+        Acquire the PID lock
+
+        :raises LockIsHeld: if lock if held
+        :raises FailedToAcquire: if for example a directory exists in that place
+        """
         try:
             self.fileno = os.open(self.path, os.O_CREAT | os.O_EXCL)
         except (IOError, OSError):
@@ -69,7 +83,7 @@ class AcquirePIDLock:
                             'PID file found but doesn''t have an int, skipping')
                         return
             except IOError as e:
-                raise FailedToAcquire()
+                raise FailedToAcquire(repr(e))
 
             # Is this process alive?
             try:
@@ -81,17 +95,15 @@ class AcquirePIDLock:
 
     def __enter__(self):
         try:
-            self._acquire()
+            self.acquire()
         except LockIsHeld as e:
             if self.delete_on_dead and (not e.is_alive):
                 os.unlink(self.path)
-                self._acquire()
+                self.acquire()
             else:
                 raise
 
         self.success = True
 
     def __exit__(self, exc_type, exc_val, exc_tb):
-        if self.fileno is not None:
-            os.close(self.fileno)
-            os.unlink(self.path)
+        self.release()
diff --git a/satella/posix/signals.py b/satella/posix/signals.py
index 9c3b1959c695b572b61e350b9e349f8e3f4b6c56..ad51aa5ab2b9ada86eee314c6d6b98ce140719d3 100644
--- a/satella/posix/signals.py
+++ b/satella/posix/signals.py
@@ -14,10 +14,14 @@ def __sighandler(a, b):
     end = True
 
 
-def hang_until_sig(extra_signals: tp.Optional[tp.List] = None):
-    """Will hang until this process receives SIGTERM or SIGINT.
+def hang_until_sig(extra_signals: tp.Optional[tp.List[int]] = None):
+    """
+    Will hang until this process receives SIGTERM or SIGINT.
     If you pass extra signal IDs (signal.SIG*) with extra_signals,
-    then also on those signals this call will release."""
+    then also on those signals this call will release.
+
+    :param extra_signals: a list of extra signals to listen to
+    """
     extra_signals = extra_signals or []
     global end