]> granicus.if.org Git - python/commitdiff
bpo-38116: Convert select module to PEP-384 (#15971)
authorDino Viehland <dinoviehland@gmail.com>
Sat, 14 Sep 2019 14:20:27 +0000 (15:20 +0100)
committerGitHub <noreply@github.com>
Sat, 14 Sep 2019 14:20:27 +0000 (15:20 +0100)
* Convert select module to PEP-384

Summary: Do the necessary versions to be Pyro-compatible, including migrating `PyType_Ready` to `PyType_FromSpec` and moving static data into a new `_selectstate` struct.

* ðŸ“œðŸ¤– Added by blurb_it.

* Fixup Mac OS/X build

Misc/NEWS.d/next/Core and Builtins/2019-09-11-14-49-42.bpo-38116.KDwmwt.rst [new file with mode: 0644]
Modules/clinic/selectmodule.c.h
Modules/selectmodule.c

diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-09-11-14-49-42.bpo-38116.KDwmwt.rst b/Misc/NEWS.d/next/Core and Builtins/2019-09-11-14-49-42.bpo-38116.KDwmwt.rst
new file mode 100644 (file)
index 0000000..d6d630b
--- /dev/null
@@ -0,0 +1 @@
+The select module is now PEP-384 compliant and no longer has static state
\ No newline at end of file
index 9015816f80c1437be5d97abbb65194278037884c..670af6a3d8de6cccc30405331c839e1c6813e01c 100644 (file)
@@ -959,11 +959,11 @@ select_kqueue(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
     PyObject *return_value = NULL;
 
-    if ((type == &kqueue_queue_Type) &&
+    if ((type == _selectstate_global->kqueue_queue_Type) &&
         !_PyArg_NoPositional("kqueue", args)) {
         goto exit;
     }
-    if ((type == &kqueue_queue_Type) &&
+    if ((type == _selectstate_global->kqueue_queue_Type) &&
         !_PyArg_NoKeywords("kqueue", kwargs)) {
         goto exit;
     }
@@ -1215,4 +1215,4 @@ exit:
 #ifndef SELECT_KQUEUE_CONTROL_METHODDEF
     #define SELECT_KQUEUE_CONTROL_METHODDEF
 #endif /* !defined(SELECT_KQUEUE_CONTROL_METHODDEF) */
-/*[clinic end generated code: output=03041f3d09b04a3d input=a9049054013a1b77]*/
+/*[clinic end generated code: output=26bb05e5fba2bfd1 input=a9049054013a1b77]*/
index 2e06a897132a846ca3522389a9f0ed7168ddd3b8..98da7d5027f4a524f60c19f4b26883a433bc0720 100644 (file)
@@ -58,14 +58,28 @@ extern void bzero(void *, int);
 #  define SOCKET int
 #endif
 
+typedef struct {
+    PyObject *close;
+    PyTypeObject *poll_Type;
+    PyTypeObject *devpoll_Type;
+    PyTypeObject *pyEpoll_Type;
+    PyTypeObject *kqueue_event_Type;
+    PyTypeObject *kqueue_queue_Type;
+} _selectstate;
+
+static struct PyModuleDef selectmodule;
+
+#define _selectstate(o) ((_selectstate *)PyModule_GetState(o))
+#define _selectstate_global _selectstate(PyState_FindModule(&selectmodule))
+
 /*[clinic input]
 module select
 class select.poll "pollObject *" "&poll_Type"
 class select.devpoll "devpollObject *" "&devpoll_Type"
 class select.epoll "pyEpoll_Object *" "&pyEpoll_Type"
-class select.kqueue "kqueue_queue_Object *" "&kqueue_queue_Type"
+class select.kqueue "kqueue_queue_Object *" "_selectstate_global->kqueue_queue_Type"
 [clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ded80abdad2b7552]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=41071028e0ede093]*/
 
 static int
 fildes_converter(PyObject *o, void *p)
@@ -400,8 +414,6 @@ typedef struct {
     int poll_running;
 } pollObject;
 
-static PyTypeObject poll_Type;
-
 /* Update the malloc'ed array of pollfds to match the dictionary
    contained within a pollObject.  Return 1 on success, 0 on an error.
 */
@@ -709,7 +721,7 @@ static pollObject *
 newPollObject(void)
 {
     pollObject *self;
-    self = PyObject_New(pollObject, &poll_Type);
+    self = PyObject_New(pollObject, _selectstate_global->poll_Type);
     if (self == NULL)
         return NULL;
     /* ufd_uptodate is a Boolean, denoting whether the
@@ -725,13 +737,22 @@ newPollObject(void)
     return self;
 }
 
+static PyObject *
+poll_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+    PyErr_Format(PyExc_TypeError, "Cannot create '%.200s' instances", _PyType_Name(type));
+    return NULL;
+}
+
 static void
 poll_dealloc(pollObject *self)
 {
+    PyObject* type = (PyObject *)Py_TYPE(self);
     if (self->ufds != NULL)
         PyMem_DEL(self->ufds);
     Py_XDECREF(self->dict);
     PyObject_Del(self);
+    Py_DECREF(type);
 }
 
 
@@ -744,8 +765,6 @@ typedef struct {
     struct pollfd *fds;
 } devpollObject;
 
-static PyTypeObject devpoll_Type;
-
 static PyObject *
 devpoll_err_closed(void)
 {
@@ -1091,7 +1110,7 @@ newDevPollObject(void)
         return NULL;
     }
 
-    self = PyObject_New(devpollObject, &devpoll_Type);
+    self = PyObject_New(devpollObject, _selectstate_global->devpoll_Type);
     if (self == NULL) {
         close(fd_devpoll);
         PyMem_DEL(fds);
@@ -1105,14 +1124,39 @@ newDevPollObject(void)
     return self;
 }
 
+static PyObject *
+devpoll_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+    PyErr_Format(PyExc_TypeError, "Cannot create '%.200s' instances", _PyType_Name(type));
+    return NULL;
+}
+
 static void
 devpoll_dealloc(devpollObject *self)
 {
+    PyObject *type = (PyObject *)Py_TYPE(self);
     (void)devpoll_internal_close(self);
     PyMem_DEL(self->fds);
     PyObject_Del(self);
+    Py_DECREF(type);
 }
 
+static PyType_Slot devpoll_Type_slots[] = {
+    {Py_tp_dealloc, devpoll_dealloc},
+    {Py_tp_getset, devpoll_getsetlist},
+    {Py_tp_methods, devpoll_methods},
+    {Py_tp_new, devpoll_new},
+    {0, 0},
+};
+
+static PyType_Spec devpoll_Type_spec = {
+    "select.devpoll",
+    sizeof(devpollObject),
+    0,
+    Py_TPFLAGS_DEFAULT,
+    devpoll_Type_slots
+};
+
 #endif  /* HAVE_SYS_DEVPOLL_H */
 
 
@@ -1201,8 +1245,7 @@ typedef struct {
     SOCKET epfd;                        /* epoll control file descriptor */
 } pyEpoll_Object;
 
-static PyTypeObject pyEpoll_Type;
-#define pyepoll_CHECK(op) (PyObject_TypeCheck((op), &pyEpoll_Type))
+#define pyepoll_CHECK(op) (PyObject_TypeCheck((op), _selectstate_global->pyEpoll_Type))
 
 static PyObject *
 pyepoll_err_closed(void)
@@ -1230,9 +1273,10 @@ static PyObject *
 newPyEpoll_Object(PyTypeObject *type, int sizehint, SOCKET fd)
 {
     pyEpoll_Object *self;
-
-    assert(type != NULL && type->tp_alloc != NULL);
-    self = (pyEpoll_Object *) type->tp_alloc(type, 0);
+    assert(type != NULL);
+    allocfunc epoll_alloc = PyType_GetSlot(type, Py_tp_alloc);
+    assert(epoll_alloc != NULL);
+    self = (pyEpoll_Object *) epoll_alloc(type, 0);
     if (self == NULL)
         return NULL;
 
@@ -1307,8 +1351,11 @@ select_epoll_impl(PyTypeObject *type, int sizehint, int flags)
 static void
 pyepoll_dealloc(pyEpoll_Object *self)
 {
+    PyTypeObject* type = Py_TYPE(self);
     (void)pyepoll_internal_close(self);
-    Py_TYPE(self)->tp_free(self);
+    freefunc epoll_free = PyType_GetSlot(type, Py_tp_free);
+    epoll_free((PyObject *)self);
+    Py_DECREF((PyObject *)type);
 }
 
 /*[clinic input]
@@ -1632,9 +1679,7 @@ select_epoll___exit___impl(pyEpoll_Object *self, PyObject *exc_type,
                            PyObject *exc_value, PyObject *exc_tb)
 /*[clinic end generated code: output=c480f38ce361748e input=7ae81a5a4c1a98d8]*/
 {
-    _Py_IDENTIFIER(close);
-
-    return _PyObject_CallMethodIdNoArgs((PyObject *)self, &PyId_close);
+    return PyObject_CallMethodObjArgs((PyObject *)self, _selectstate_global->close, NULL);
 }
 
 static PyGetSetDef pyepoll_getsetlist[] = {
@@ -1643,6 +1688,15 @@ static PyGetSetDef pyepoll_getsetlist[] = {
     {0},
 };
 
+PyDoc_STRVAR(pyepoll_doc,
+"select.epoll(sizehint=-1, flags=0)\n\
+\n\
+Returns an epolling object\n\
+\n\
+sizehint must be a positive integer or -1 for the default size. The\n\
+sizehint is used to optimize internal data structures. It doesn't limit\n\
+the maximum number of monitored events.");
+
 #endif /* HAVE_EPOLL */
 
 #ifdef HAVE_KQUEUE
@@ -1699,18 +1753,14 @@ typedef struct {
     struct kevent e;
 } kqueue_event_Object;
 
-static PyTypeObject kqueue_event_Type;
-
-#define kqueue_event_Check(op) (PyObject_TypeCheck((op), &kqueue_event_Type))
+#define kqueue_event_Check(op) (PyObject_TypeCheck((op), _selectstate_global->kqueue_event_Type))
 
 typedef struct {
     PyObject_HEAD
     SOCKET kqfd;                /* kqueue control fd */
 } kqueue_queue_Object;
 
-static PyTypeObject kqueue_queue_Type;
-
-#define kqueue_queue_Check(op) (PyObject_TypeCheck((op), &kqueue_queue_Type))
+#define kqueue_queue_Check(op) (PyObject_TypeCheck((op), _selectstate_global->kqueue_queue_Type))
 
 #if (SIZEOF_UINTPTR_T != SIZEOF_VOID_P)
 #   error uintptr_t does not match void *!
@@ -1870,6 +1920,24 @@ kqueue_event_richcompare(kqueue_event_Object *s, kqueue_event_Object *o,
     Py_RETURN_RICHCOMPARE(result, 0, op);
 }
 
+static PyType_Slot kqueue_event_Type_slots[] = {
+    {Py_tp_doc, (void*)kqueue_event_doc},
+    {Py_tp_init, kqueue_event_init},
+    {Py_tp_members, kqueue_event_members},
+    {Py_tp_new, PyType_GenericNew},
+    {Py_tp_repr, kqueue_event_repr},
+    {Py_tp_richcompare, kqueue_event_richcompare},
+    {0, 0},
+};
+
+static PyType_Spec kqueue_event_Type_spec = {
+    "select.kevent",
+    sizeof(kqueue_event_Object),
+    0,
+    Py_TPFLAGS_DEFAULT,
+    kqueue_event_Type_slots
+};
+
 static PyObject *
 kqueue_queue_err_closed(void)
 {
@@ -1896,8 +1964,10 @@ static PyObject *
 newKqueue_Object(PyTypeObject *type, SOCKET fd)
 {
     kqueue_queue_Object *self;
-    assert(type != NULL && type->tp_alloc != NULL);
-    self = (kqueue_queue_Object *) type->tp_alloc(type, 0);
+    assert(type != NULL);
+    allocfunc queue_alloc = PyType_GetSlot(type, Py_tp_alloc);
+    assert(queue_alloc != NULL);
+    self = (kqueue_queue_Object *) queue_alloc(type, 0);
     if (self == NULL) {
         return NULL;
     }
@@ -1954,8 +2024,11 @@ select_kqueue_impl(PyTypeObject *type)
 static void
 kqueue_queue_dealloc(kqueue_queue_Object *self)
 {
+    PyTypeObject* type = Py_TYPE(self);
     kqueue_queue_internal_close(self);
-    Py_TYPE(self)->tp_free(self);
+    freefunc kqueue_free = PyType_GetSlot(type, Py_tp_free);
+    kqueue_free((PyObject *)self);
+    Py_DECREF((PyObject *)type);
 }
 
 /*[clinic input]
@@ -2072,7 +2145,7 @@ select_kqueue_control_impl(kqueue_queue_Object *self, PyObject *changelist,
             PyErr_Format(PyExc_TypeError,
                 "timeout argument must be a number "
                 "or None, got %.200s",
-                Py_TYPE(otimeout)->tp_name);
+                _PyType_Name(Py_TYPE(otimeout)));
             return NULL;
         }
 
@@ -2168,7 +2241,7 @@ select_kqueue_control_impl(kqueue_queue_Object *self, PyObject *changelist,
     for (i = 0; i < gotevents; i++) {
         kqueue_event_Object *ch;
 
-        ch = PyObject_New(kqueue_event_Object, &kqueue_event_Type);
+        ch = PyObject_New(kqueue_event_Object, _selectstate_global->kqueue_event_Type);
         if (ch == NULL) {
             goto error;
         }
@@ -2210,38 +2283,20 @@ static PyMethodDef poll_methods[] = {
     {NULL, NULL}           /* sentinel */
 };
 
-static PyTypeObject poll_Type = {
-    /* The ob_type field must be initialized in the module init function
-     * to be portable to Windows without using C++. */
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "select.poll",              /*tp_name*/
-    sizeof(pollObject),         /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    /* methods */
-    (destructor)poll_dealloc, /*tp_dealloc*/
-    0,                          /*tp_vectorcall_offset*/
-    0,                          /*tp_getattr*/
-    0,                      /*tp_setattr*/
-    0,                          /*tp_as_async*/
-    0,                          /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash*/
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT,         /*tp_flags*/
-    0,                          /*tp_doc*/
-    0,                          /*tp_traverse*/
-    0,                          /*tp_clear*/
-    0,                          /*tp_richcompare*/
-    0,                          /*tp_weaklistoffset*/
-    0,                          /*tp_iter*/
-    0,                          /*tp_iternext*/
-    poll_methods,               /*tp_methods*/
+
+static PyType_Slot poll_Type_slots[] = {
+    {Py_tp_dealloc, poll_dealloc},
+    {Py_tp_methods, poll_methods},
+    {Py_tp_new, poll_new},
+    {0, 0},
+};
+
+static PyType_Spec poll_Type_spec = {
+    "select.poll",
+    sizeof(pollObject),
+    0,
+    Py_TPFLAGS_DEFAULT,
+    poll_Type_slots
 };
 
 #ifdef HAVE_SYS_DEVPOLL_H
@@ -2256,42 +2311,6 @@ static PyMethodDef devpoll_methods[] = {
     {NULL,              NULL}           /* sentinel */
 };
 
-static PyTypeObject devpoll_Type = {
-    /* The ob_type field must be initialized in the module init function
-     * to be portable to Windows without using C++. */
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "select.devpoll",           /*tp_name*/
-    sizeof(devpollObject),      /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    /* methods */
-    (destructor)devpoll_dealloc, /*tp_dealloc*/
-    0,                          /*tp_vectorcall_offset*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_as_async*/
-    0,                          /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash*/
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT,         /*tp_flags*/
-    0,                          /*tp_doc*/
-    0,                          /*tp_traverse*/
-    0,                          /*tp_clear*/
-    0,                          /*tp_richcompare*/
-    0,                          /*tp_weaklistoffset*/
-    0,                          /*tp_iter*/
-    0,                          /*tp_iternext*/
-    devpoll_methods,            /*tp_methods*/
-    0,                          /* tp_members */
-    devpoll_getsetlist,         /* tp_getset */
-};
-
 #endif  /* HAVE_SYS_DEVPOLL_H */
 
 #endif /* HAVE_POLL */
@@ -2311,94 +2330,28 @@ static PyMethodDef pyepoll_methods[] = {
     {NULL,      NULL},
 };
 
-static PyTypeObject pyEpoll_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "select.epoll",                                     /* tp_name */
-    sizeof(pyEpoll_Object),                             /* tp_basicsize */
-    0,                                                  /* tp_itemsize */
-    (destructor)pyepoll_dealloc,                        /* tp_dealloc */
-    0,                                                  /* tp_vectorcall_offset */
-    0,                                                  /* tp_getattr */
-    0,                                                  /* tp_setattr */
-    0,                                                  /* tp_as_async */
-    0,                                                  /* tp_repr */
-    0,                                                  /* tp_as_number */
-    0,                                                  /* tp_as_sequence */
-    0,                                                  /* tp_as_mapping */
-    0,                                                  /* tp_hash */
-    0,                                                  /* tp_call */
-    0,                                                  /* tp_str */
-    PyObject_GenericGetAttr,                            /* tp_getattro */
-    0,                                                  /* tp_setattro */
-    0,                                                  /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT,                                 /* tp_flags */
-    select_epoll__doc__,                                /* tp_doc */
-    0,                                                  /* tp_traverse */
-    0,                                                  /* tp_clear */
-    0,                                                  /* tp_richcompare */
-    0,                                                  /* tp_weaklistoffset */
-    0,                                                  /* tp_iter */
-    0,                                                  /* tp_iternext */
-    pyepoll_methods,                                    /* tp_methods */
-    0,                                                  /* tp_members */
-    pyepoll_getsetlist,                                 /* tp_getset */
-    0,                                                  /* tp_base */
-    0,                                                  /* tp_dict */
-    0,                                                  /* tp_descr_get */
-    0,                                                  /* tp_descr_set */
-    0,                                                  /* tp_dictoffset */
-    0,                                                  /* tp_init */
-    0,                                                  /* tp_alloc */
-    select_epoll,                                       /* tp_new */
-    0,                                                  /* tp_free */
+static PyType_Slot pyEpoll_Type_slots[] = {
+    {Py_tp_dealloc, pyepoll_dealloc},
+    {Py_tp_doc, (void*)pyepoll_doc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_getset, pyepoll_getsetlist},
+    {Py_tp_methods, pyepoll_methods},
+    {Py_tp_new, select_epoll},
+    {0, 0},
+};
+
+static PyType_Spec pyEpoll_Type_spec = {
+    "select.epoll",
+    sizeof(pyEpoll_Object),
+    0,
+    Py_TPFLAGS_DEFAULT,
+    pyEpoll_Type_slots
 };
 
 #endif /* HAVE_EPOLL */
 
 #ifdef HAVE_KQUEUE
 
-static PyTypeObject kqueue_event_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "select.kevent",                                    /* tp_name */
-    sizeof(kqueue_event_Object),                        /* tp_basicsize */
-    0,                                                  /* tp_itemsize */
-    0,                                                  /* tp_dealloc */
-    0,                                                  /* tp_vectorcall_offset */
-    0,                                                  /* tp_getattr */
-    0,                                                  /* tp_setattr */
-    0,                                                  /* tp_as_async */
-    (reprfunc)kqueue_event_repr,                        /* tp_repr */
-    0,                                                  /* tp_as_number */
-    0,                                                  /* tp_as_sequence */
-    0,                                                  /* tp_as_mapping */
-    0,                                                  /* tp_hash */
-    0,                                                  /* tp_call */
-    0,                                                  /* tp_str */
-    0,                                                  /* tp_getattro */
-    0,                                                  /* tp_setattro */
-    0,                                                  /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT,                                 /* tp_flags */
-    kqueue_event_doc,                                   /* tp_doc */
-    0,                                                  /* tp_traverse */
-    0,                                                  /* tp_clear */
-    (richcmpfunc)kqueue_event_richcompare,              /* tp_richcompare */
-    0,                                                  /* tp_weaklistoffset */
-    0,                                                  /* tp_iter */
-    0,                                                  /* tp_iternext */
-    0,                                                  /* tp_methods */
-    kqueue_event_members,                               /* tp_members */
-    0,                                                  /* tp_getset */
-    0,                                                  /* tp_base */
-    0,                                                  /* tp_dict */
-    0,                                                  /* tp_descr_get */
-    0,                                                  /* tp_descr_set */
-    0,                                                  /* tp_dictoffset */
-    (initproc)kqueue_event_init,                        /* tp_init */
-    0,                                                  /* tp_alloc */
-    0,                                                  /* tp_new */
-    0,                                                  /* tp_free */
-};
-
 static PyMethodDef kqueue_queue_methods[] = {
     SELECT_KQUEUE_FROMFD_METHODDEF
     SELECT_KQUEUE_CLOSE_METHODDEF
@@ -2407,46 +2360,21 @@ static PyMethodDef kqueue_queue_methods[] = {
     {NULL,      NULL},
 };
 
-static PyTypeObject kqueue_queue_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "select.kqueue",                                    /* tp_name */
-    sizeof(kqueue_queue_Object),                        /* tp_basicsize */
-    0,                                                  /* tp_itemsize */
-    (destructor)kqueue_queue_dealloc,                   /* tp_dealloc */
-    0,                                                  /* tp_vectorcall_offset */
-    0,                                                  /* tp_getattr */
-    0,                                                  /* tp_setattr */
-    0,                                                  /* tp_as_async */
-    0,                                                  /* tp_repr */
-    0,                                                  /* tp_as_number */
-    0,                                                  /* tp_as_sequence */
-    0,                                                  /* tp_as_mapping */
-    0,                                                  /* tp_hash */
-    0,                                                  /* tp_call */
-    0,                                                  /* tp_str */
-    0,                                                  /* tp_getattro */
-    0,                                                  /* tp_setattro */
-    0,                                                  /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT,                                 /* tp_flags */
-    select_kqueue__doc__,                               /* tp_doc */
-    0,                                                  /* tp_traverse */
-    0,                                                  /* tp_clear */
-    0,                                                  /* tp_richcompare */
-    0,                                                  /* tp_weaklistoffset */
-    0,                                                  /* tp_iter */
-    0,                                                  /* tp_iternext */
-    kqueue_queue_methods,                               /* tp_methods */
-    0,                                                  /* tp_members */
-    kqueue_queue_getsetlist,                            /* tp_getset */
-    0,                                                  /* tp_base */
-    0,                                                  /* tp_dict */
-    0,                                                  /* tp_descr_get */
-    0,                                                  /* tp_descr_set */
-    0,                                                  /* tp_dictoffset */
-    0,                                                  /* tp_init */
-    0,                                                  /* tp_alloc */
-    select_kqueue,                                      /* tp_new */
-    0,                                                  /* tp_free */
+static PyType_Slot kqueue_queue_Type_slots[] = {
+    {Py_tp_dealloc, kqueue_queue_dealloc},
+    {Py_tp_doc, select_kqueue__doc__},
+    {Py_tp_getset, kqueue_queue_getsetlist},
+    {Py_tp_methods, kqueue_queue_methods},
+    {Py_tp_new, select_kqueue},
+    {0, 0},
+};
+
+static PyType_Spec kqueue_queue_Type_spec = {
+    "select.kqueue",
+    sizeof(kqueue_queue_Object),
+    0,
+    Py_TPFLAGS_DEFAULT,
+    kqueue_queue_Type_slots
 };
 
 #endif /* HAVE_KQUEUE */
@@ -2472,21 +2400,49 @@ PyDoc_STRVAR(module_doc,
 On Windows, only sockets are supported; on Unix, all file descriptors.");
 
 
+
+static int
+_select_traverse(PyObject *module, visitproc visit, void *arg)
+{
+    Py_VISIT(_selectstate(module)->close);
+    Py_VISIT(_selectstate(module)->poll_Type);
+    Py_VISIT(_selectstate(module)->devpoll_Type);
+    Py_VISIT(_selectstate(module)->pyEpoll_Type);
+    Py_VISIT(_selectstate(module)->kqueue_event_Type);
+    Py_VISIT(_selectstate(module)->kqueue_queue_Type);
+    return 0;
+}
+
+static int
+_select_clear(PyObject *module)
+{
+    Py_CLEAR(_selectstate(module)->close);
+    Py_CLEAR(_selectstate(module)->poll_Type);
+    Py_CLEAR(_selectstate(module)->devpoll_Type);
+    Py_CLEAR(_selectstate(module)->pyEpoll_Type);
+    Py_CLEAR(_selectstate(module)->kqueue_event_Type);
+    Py_CLEAR(_selectstate(module)->kqueue_queue_Type);
+    return 0;
+}
+
+static void
+_select_free(void *module)
+{
+    _select_clear((PyObject *)module);
+}
+
 static struct PyModuleDef selectmodule = {
     PyModuleDef_HEAD_INIT,
     "select",
     module_doc,
-    -1,
+    sizeof(_selectstate),
     select_methods,
     NULL,
-    NULL,
-    NULL,
-    NULL
+    _select_traverse,
+    _select_clear,
+    _select_free,
 };
 
-
-
-
 PyMODINIT_FUNC
 PyInit_select(void)
 {
@@ -2495,6 +2451,8 @@ PyInit_select(void)
     if (m == NULL)
         return NULL;
 
+    _selectstate(m)->close = PyUnicode_InternFromString("close");
+
     Py_INCREF(PyExc_OSError);
     PyModule_AddObject(m, "error", PyExc_OSError);
 
@@ -2516,8 +2474,12 @@ PyInit_select(void)
 #else
     {
 #endif
-        if (PyType_Ready(&poll_Type) < 0)
+        PyObject *poll_Type = PyType_FromSpec(&poll_Type_spec);
+        if (poll_Type == NULL)
             return NULL;
+        _selectstate(m)->poll_Type = (PyTypeObject *)poll_Type;
+        Py_INCREF(poll_Type);
+
         PyModule_AddIntMacro(m, POLLIN);
         PyModule_AddIntMacro(m, POLLPRI);
         PyModule_AddIntMacro(m, POLLOUT);
@@ -2548,17 +2510,20 @@ PyInit_select(void)
 #endif /* HAVE_POLL */
 
 #ifdef HAVE_SYS_DEVPOLL_H
-    if (PyType_Ready(&devpoll_Type) < 0)
+    PyObject *devpoll_Type = PyType_FromSpec(&devpoll_Type_spec);
+    if (devpoll_Type == NULL)
         return NULL;
+    _selectstate(m)->devpoll_Type = (PyTypeObject *)devpoll_Type;
+    Py_INCREF(devpoll_Type);
 #endif
 
 #ifdef HAVE_EPOLL
-    Py_TYPE(&pyEpoll_Type) = &PyType_Type;
-    if (PyType_Ready(&pyEpoll_Type) < 0)
+    PyObject *pyEpoll_Type = PyType_FromSpec(&pyEpoll_Type_spec);
+    if (pyEpoll_Type == NULL)
         return NULL;
-
-    Py_INCREF(&pyEpoll_Type);
-    PyModule_AddObject(m, "epoll", (PyObject *) &pyEpoll_Type);
+    _selectstate(m)->pyEpoll_Type = (PyTypeObject *)pyEpoll_Type;
+    Py_INCREF(pyEpoll_Type);
+    PyModule_AddObject(m, "epoll", (PyObject *)_selectstate(m)->pyEpoll_Type);
 
     PyModule_AddIntMacro(m, EPOLLIN);
     PyModule_AddIntMacro(m, EPOLLOUT);
@@ -2600,19 +2565,19 @@ PyInit_select(void)
 #endif /* HAVE_EPOLL */
 
 #ifdef HAVE_KQUEUE
-    kqueue_event_Type.tp_new = PyType_GenericNew;
-    Py_TYPE(&kqueue_event_Type) = &PyType_Type;
-    if(PyType_Ready(&kqueue_event_Type) < 0)
+    PyObject *kqueue_event_Type = PyType_FromSpec(&kqueue_event_Type_spec);
+    if (kqueue_event_Type == NULL)
         return NULL;
+    _selectstate(m)->kqueue_event_Type = (PyTypeObject *)kqueue_event_Type;
+    Py_INCREF(_selectstate(m)->kqueue_event_Type);
+    PyModule_AddObject(m, "kevent", kqueue_event_Type);
 
-    Py_INCREF(&kqueue_event_Type);
-    PyModule_AddObject(m, "kevent", (PyObject *)&kqueue_event_Type);
-
-    Py_TYPE(&kqueue_queue_Type) = &PyType_Type;
-    if(PyType_Ready(&kqueue_queue_Type) < 0)
+    PyObject *kqueue_queue_Type = PyType_FromSpec(&kqueue_queue_Type_spec);
+    if (kqueue_queue_Type == NULL)
         return NULL;
-    Py_INCREF(&kqueue_queue_Type);
-    PyModule_AddObject(m, "kqueue", (PyObject *)&kqueue_queue_Type);
+    _selectstate(m)->kqueue_queue_Type = (PyTypeObject *)kqueue_queue_Type;
+    Py_INCREF(_selectstate(m)->kqueue_queue_Type);
+    PyModule_AddObject(m, "kqueue", kqueue_queue_Type);
 
     /* event filters */
     PyModule_AddIntConstant(m, "KQ_FILTER_READ", EVFILT_READ);