asyncio, Tulip issue 139: Improve error messages on "fatal errors"

Mention if the error was caused by a read or a write, and be more specific on
the object (ex: "pipe transport" instead of "transport").
diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py
index d72f927..f45cd9c 100644
--- a/Lib/asyncio/proactor_events.py
+++ b/Lib/asyncio/proactor_events.py
@@ -53,10 +53,10 @@
         if self._read_fut is not None:
             self._read_fut.cancel()
 
-    def _fatal_error(self, exc):
+    def _fatal_error(self, exc, message='Fatal error on pipe transport'):
         if not isinstance(exc, (BrokenPipeError, ConnectionResetError)):
             self._loop.call_exception_handler({
-                'message': 'Fatal transport error',
+                'message': message,
                 'exception': exc,
                 'transport': self,
                 'protocol': self._protocol,
@@ -151,11 +151,11 @@
             self._read_fut = self._loop._proactor.recv(self._sock, 4096)
         except ConnectionAbortedError as exc:
             if not self._closing:
-                self._fatal_error(exc)
+                self._fatal_error(exc, 'Fatal read error on pipe transport')
         except ConnectionResetError as exc:
             self._force_close(exc)
         except OSError as exc:
-            self._fatal_error(exc)
+            self._fatal_error(exc, 'Fatal read error on pipe transport')
         except futures.CancelledError:
             if not self._closing:
                 raise
@@ -246,7 +246,7 @@
         except ConnectionResetError as exc:
             self._force_close(exc)
         except OSError as exc:
-            self._fatal_error(exc)
+            self._fatal_error(exc, 'Fatal write error on pipe transport')
 
     def can_write_eof(self):
         return True
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index 869d66e..c142356 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -377,11 +377,11 @@
             self._conn_lost += 1
             self._loop.call_soon(self._call_connection_lost, None)
 
-    def _fatal_error(self, exc):
+    def _fatal_error(self, exc, message='Fatal error on transport'):
         # Should be called from exception handler only.
         if not isinstance(exc, (BrokenPipeError, ConnectionResetError)):
             self._loop.call_exception_handler({
-                'message': 'Fatal transport error',
+                'message': message,
                 'exception': exc,
                 'transport': self,
                 'protocol': self._protocol,
@@ -452,7 +452,7 @@
         except (BlockingIOError, InterruptedError):
             pass
         except Exception as exc:
-            self._fatal_error(exc)
+            self._fatal_error(exc, 'Fatal read error on socket transport')
         else:
             if data:
                 self._protocol.data_received(data)
@@ -488,7 +488,7 @@
             except (BlockingIOError, InterruptedError):
                 pass
             except Exception as exc:
-                self._fatal_error(exc)
+                self._fatal_error(exc, 'Fatal write error on socket transport')
                 return
             else:
                 data = data[n:]
@@ -511,7 +511,7 @@
         except Exception as exc:
             self._loop.remove_writer(self._sock_fd)
             self._buffer.clear()
-            self._fatal_error(exc)
+            self._fatal_error(exc, 'Fatal write error on socket transport')
         else:
             if n:
                 del self._buffer[:n]
@@ -678,7 +678,7 @@
             self._loop.remove_reader(self._sock_fd)
             self._loop.add_writer(self._sock_fd, self._write_ready)
         except Exception as exc:
-            self._fatal_error(exc)
+            self._fatal_error(exc, 'Fatal read error on SSL transport')
         else:
             if data:
                 self._protocol.data_received(data)
@@ -712,7 +712,7 @@
             except Exception as exc:
                 self._loop.remove_writer(self._sock_fd)
                 self._buffer.clear()
-                self._fatal_error(exc)
+                self._fatal_error(exc, 'Fatal write error on SSL transport')
                 return
 
             if n:
@@ -770,7 +770,7 @@
         except OSError as exc:
             self._protocol.error_received(exc)
         except Exception as exc:
-            self._fatal_error(exc)
+            self._fatal_error(exc, 'Fatal read error on datagram transport')
         else:
             self._protocol.datagram_received(data, addr)
 
@@ -805,7 +805,8 @@
                 self._protocol.error_received(exc)
                 return
             except Exception as exc:
-                self._fatal_error(exc)
+                self._fatal_error(exc,
+                                  'Fatal write error on datagram transport')
                 return
 
         # Ensure that what we buffer is immutable.
@@ -827,7 +828,8 @@
                 self._protocol.error_received(exc)
                 return
             except Exception as exc:
-                self._fatal_error(exc)
+                self._fatal_error(exc,
+                                  'Fatal write error on datagram transport')
                 return
 
         self._maybe_resume_protocol()  # May append to buffer.
diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py
index 748452c..3a2fd18 100644
--- a/Lib/asyncio/unix_events.py
+++ b/Lib/asyncio/unix_events.py
@@ -271,7 +271,7 @@
         except (BlockingIOError, InterruptedError):
             pass
         except OSError as exc:
-            self._fatal_error(exc)
+            self._fatal_error(exc, 'Fatal read error on pipe transport')
         else:
             if data:
                 self._protocol.data_received(data)
@@ -291,11 +291,11 @@
         if not self._closing:
             self._close(None)
 
-    def _fatal_error(self, exc):
+    def _fatal_error(self, exc, message='Fatal error on pipe transport'):
         # should be called by exception handler only
         if not (isinstance(exc, OSError) and exc.errno == errno.EIO):
             self._loop.call_exception_handler({
-                'message': 'Fatal transport error',
+                'message': message,
                 'exception': exc,
                 'transport': self,
                 'protocol': self._protocol,
@@ -381,7 +381,7 @@
                 n = 0
             except Exception as exc:
                 self._conn_lost += 1
-                self._fatal_error(exc)
+                self._fatal_error(exc, 'Fatal write error on pipe transport')
                 return
             if n == len(data):
                 return
@@ -406,7 +406,7 @@
             # Remove writer here, _fatal_error() doesn't it
             # because _buffer is empty.
             self._loop.remove_writer(self._fileno)
-            self._fatal_error(exc)
+            self._fatal_error(exc, 'Fatal write error on pipe transport')
         else:
             if n == len(data):
                 self._loop.remove_writer(self._fileno)
@@ -443,11 +443,11 @@
     def abort(self):
         self._close(None)
 
-    def _fatal_error(self, exc):
+    def _fatal_error(self, exc, message='Fatal error on pipe transport'):
         # should be called by exception handler only
         if not isinstance(exc, (BrokenPipeError, ConnectionResetError)):
             self._loop.call_exception_handler({
-                'message': 'Fatal transport error',
+                'message': message,
                 'exception': exc,
                 'transport': self,
                 'protocol': self._protocol,