Issue #12011: signal.signal() and signal.siginterrupt() raise an OSError,
instead of a RuntimeError: OSError has an errno attribute.
diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst
index e657af2..d442665 100644
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -148,6 +148,9 @@
   a nul byte into the wakeup file descriptor. So it is possible to wait more
   than one signal and know which signals were raised.
 
+* :func:`signal.signal` and :func:`signal.siginterrupt` raise an OSError,
+  instead of a RuntimeError: OSError has an errno attribute.
+
 
 Optimizations
 =============
diff --git a/Misc/NEWS b/Misc/NEWS
index 5953d30..2b0529e 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -143,6 +143,9 @@
 Library
 -------
 
+- Issue #12011: signal.signal() and signal.siginterrupt() raise an OSError,
+  instead of a RuntimeError: OSError has an errno attribute.
+
 - Issue #3709: a flush_headers method to BaseHTTPRequestHandler which manages
   the sending of headers to output stream and flushing the internal headers
   buffer. Patch contribution by Andrew Schaaf
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index e504669..feeae5e 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -324,7 +324,7 @@
     else
         func = signal_handler;
     if (PyOS_setsig(sig_num, func) == SIG_ERR) {
-        PyErr_SetFromErrno(PyExc_RuntimeError);
+        PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }
     old_handler = Handlers[sig_num].func;
@@ -393,7 +393,7 @@
         return NULL;
     }
     if (siginterrupt(sig_num, flag)<0) {
-        PyErr_SetFromErrno(PyExc_RuntimeError);
+        PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }