Issue #11223: Replace threading._info() by sys.thread_info
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index fdf361f..b549203 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -17,6 +17,7 @@
 #include "Python.h"
 #include "code.h"
 #include "frameobject.h"
+#include "pythread.h"
 
 #include "osdefs.h"
 
@@ -1251,20 +1252,21 @@
 "\n\
 Static objects:\n\
 \n\
-float_info -- a dict with information about the float implementation.\n\
+builtin_module_names -- tuple of module names built into this interpreter\n\
+copyright -- copyright notice pertaining to this interpreter\n\
+exec_prefix -- prefix used to find the machine-specific Python library\n\
+executable -- pathname of this Python interpreter\n\
+float_info -- a struct sequence with information about the float implementation.\n\
+float_repr_style -- string indicating the style of repr() output for floats\n\
+hexversion -- version information encoded as a single integer\n\
 int_info -- a struct sequence with information about the int implementation.\n\
 maxsize -- the largest supported length of containers.\n\
 maxunicode -- the largest supported character\n\
-builtin_module_names -- tuple of module names built into this interpreter\n\
+platform -- platform identifier\n\
+prefix -- prefix used to find the Python library\n\
+thread_info -- a struct sequence with information about the thread implementation.\n\
 version -- the version of this interpreter as a string\n\
 version_info -- version information as a named tuple\n\
-hexversion -- version information encoded as a single integer\n\
-copyright -- copyright notice pertaining to this interpreter\n\
-platform -- platform identifier\n\
-executable -- pathname of this Python interpreter\n\
-prefix -- prefix used to find the Python library\n\
-exec_prefix -- prefix used to find the machine-specific Python library\n\
-float_repr_style -- string indicating the style of repr() output for floats\n\
 "
 )
 #ifdef MS_WINDOWS
@@ -1611,6 +1613,10 @@
                         PyUnicode_FromString("legacy"));
 #endif
 
+#ifdef WITH_THREAD
+    SET_SYS_FROM_STRING("thread_info", PyThread_GetInfo());
+#endif
+
 #undef SET_SYS_FROM_STRING
     if (PyErr_Occurred())
         return NULL;
diff --git a/Python/thread.c b/Python/thread.c
index 1f15a22..c7d17d6 100644
--- a/Python/thread.c
+++ b/Python/thread.c
@@ -7,7 +7,6 @@
 
 #include "Python.h"
 
-
 #ifndef _POSIX_THREADS
 /* This means pthreads are not implemented in libc headers, hence the macro
    not present in unistd.h. But they still can be implemented as an external
@@ -415,26 +414,51 @@
 
 #endif /* Py_HAVE_NATIVE_TLS */
 
+PyDoc_STRVAR(threadinfo__doc__,
+"sys.thread_info\n\
+\n\
+A struct sequence holding information about the thread implementation.");
+
+static PyStructSequence_Field threadinfo_fields[] = {
+    {"name",    "name of the thread implementation"},
+    {"lock",    "name of the lock implementation"},
+    {"version", "name and version of the thread library"},
+    {0}
+};
+
+static PyStructSequence_Desc threadinfo_desc = {
+    "sys.thread_info",           /* name */
+    threadinfo__doc__,           /* doc */
+    threadinfo_fields,           /* fields */
+    3
+};
+
+static PyTypeObject ThreadInfoType;
+
 PyObject*
-_PyThread_Info(void)
+PyThread_GetInfo(void)
 {
-    PyObject *info, *value;
-    int ret;
+    PyObject *threadinfo, *value;
+    int pos = 0;
 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
      && defined(_CS_GNU_LIBPTHREAD_VERSION))
     char buffer[255];
     int len;
 #endif
 
-    info = PyDict_New();
-    if (info == NULL)
+    if (ThreadInfoType.tp_name == 0)
+        PyStructSequence_InitType(&ThreadInfoType, &threadinfo_desc);
+
+    threadinfo = PyStructSequence_New(&ThreadInfoType);
+    if (threadinfo == NULL)
         return NULL;
 
     value = PyUnicode_FromString(PYTHREAD_NAME);
-    ret = PyDict_SetItemString(info, "name", value);
-    Py_DECREF(value);
-    if (ret)
-        goto error;
+    if (value == NULL) {
+        Py_DECREF(threadinfo);
+        return NULL;
+    }
+    PyStructSequence_SET_ITEM(threadinfo, pos++, value);
 
 #ifdef _POSIX_THREADS
 #ifdef USE_SEMAPHORES
@@ -442,30 +466,31 @@
 #else
     value = PyUnicode_FromString("mutex+cond");
 #endif
-    if (value == NULL)
+    if (value == NULL) {
+        Py_DECREF(threadinfo);
         return NULL;
-    ret = PyDict_SetItemString(info, "lock_implementation", value);
-    Py_DECREF(value);
-    if (ret)
-        goto error;
+    }
+#else
+    Py_INCREF(Py_None);
+    value = Py_None;
+#endif
+    PyStructSequence_SET_ITEM(threadinfo, pos++, value);
 
-#if defined(HAVE_CONFSTR) && defined(_CS_GNU_LIBPTHREAD_VERSION)
+#if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
+     && defined(_CS_GNU_LIBPTHREAD_VERSION))
+    value = NULL;
     len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
-    if (0 < len && len < sizeof(buffer)) {
+    if (1 < len && len < sizeof(buffer)) {
         value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
         if (value == NULL)
-            goto error;
-        ret = PyDict_SetItemString(info, "pthread_version", value);
-        Py_DECREF(value);
-        if (ret)
-            goto error;
+            PyErr_Clear();
     }
+    if (value == NULL)
 #endif
-#endif
-
-    return info;
-
-error:
-    Py_DECREF(info);
-    return NULL;
+    {
+        Py_INCREF(Py_None);
+        value = Py_None;
+    }
+    PyStructSequence_SET_ITEM(threadinfo, pos++, value);
+    return threadinfo;
 }