Issue #23694: Enhance _Py_open(), it now raises exceptions

* _Py_open() now raises exceptions on error. If open() fails, it raises an
  OSError with the filename.
* _Py_open() now releases the GIL while calling open()
* Add _Py_open_noraise() when _Py_open() cannot be used because the GIL is not
  held
diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c
index a8c2be2..a33df21 100644
--- a/Modules/_posixsubprocess.c
+++ b/Modules/_posixsubprocess.c
@@ -257,6 +257,7 @@
     fd_dir_fd = _Py_open(FD_DIR, O_RDONLY);
     if (fd_dir_fd == -1) {
         /* No way to get a list of open fds. */
+        PyErr_Clear();
         _close_fds_by_brute_force(start_fd, py_fds_to_keep);
         return;
     } else {
diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c
index ac134b8..7c4d17f 100644
--- a/Modules/mmapmodule.c
+++ b/Modules/mmapmodule.c
@@ -1221,7 +1221,6 @@
         fd = devzero = _Py_open("/dev/zero", O_RDWR);
         if (devzero == -1) {
             Py_DECREF(m_obj);
-            PyErr_SetFromErrno(PyExc_OSError);
             return NULL;
         }
 #endif
diff --git a/Modules/ossaudiodev.c b/Modules/ossaudiodev.c
index 2d0dd09..34e68c7 100644
--- a/Modules/ossaudiodev.c
+++ b/Modules/ossaudiodev.c
@@ -116,11 +116,8 @@
        provides a special ioctl() for non-blocking read/write, which is
        exposed via oss_nonblock() below. */
     fd = _Py_open(devicename, imode|O_NONBLOCK);
-
-    if (fd == -1) {
-        PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
+    if (fd == -1)
         return NULL;
-    }
 
     /* And (try to) put it back in blocking mode so we get the
        expected write() semantics. */
@@ -180,10 +177,8 @@
     }
 
     fd = _Py_open(devicename, O_RDWR);
-    if (fd == -1) {
-        PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
+    if (fd == -1)
         return NULL;
-    }
 
     if ((self = PyObject_New(oss_mixer_t, &OSSMixerType)) == NULL) {
         close(fd);
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index e47bd84..b8151c3 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -7930,7 +7930,7 @@
 
     slave_fd = _Py_open(slave_name, O_RDWR);
     if (slave_fd < 0)
-        goto posix_error;
+        goto error;
 
 #else
     master_fd = open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */
@@ -7958,8 +7958,8 @@
         goto posix_error;
 
     slave_fd = _Py_open(slave_name, O_RDWR | O_NOCTTY); /* open slave */
-    if (slave_fd < 0)
-        goto posix_error;
+    if (slave_fd == -1)
+        goto error;
 
     if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
         goto posix_error;
@@ -7977,9 +7977,7 @@
 
 posix_error:
     posix_error();
-#if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY)
 error:
-#endif
     if (master_fd != -1)
         close(master_fd);
     if (slave_fd != -1)
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
index ffaf865..ef53067 100644
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -1013,7 +1013,6 @@
     struct pollfd *fds;
     struct rlimit limit;
 
-    Py_BEGIN_ALLOW_THREADS
     /*
     ** If we try to process more that getrlimit()
     ** fds, the kernel will give an error, so
@@ -1021,18 +1020,14 @@
     ** value, because we can change rlimit() anytime.
     */
     limit_result = getrlimit(RLIMIT_NOFILE, &limit);
-    if (limit_result != -1)
-        fd_devpoll = _Py_open("/dev/poll", O_RDWR);
-    Py_END_ALLOW_THREADS
-
     if (limit_result == -1) {
         PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }
-    if (fd_devpoll == -1) {
-        PyErr_SetFromErrnoWithFilename(PyExc_IOError, "/dev/poll");
+
+    fd_devpoll = _Py_open("/dev/poll", O_RDWR);
+    if (fd_devpoll == -1)
         return NULL;
-    }
 
     fds = PyMem_NEW(struct pollfd, limit.rlim_cur);
     if (fds == NULL) {