bpo-36710: Add runtime parameter to _PyThreadState_Init() (GH-12935)

* Add 'runtime' parameter to _PyThreadState_Init()
* Add 'gilstate' parameter to _PyGILState_NoteThreadState()
* Move _PyThreadState_Init() and _PyThreadState_DeleteExcept()
   to the internal C API.
diff --git a/Python/pystate.c b/Python/pystate.c
index a2464b6..ef9d792 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -133,7 +133,9 @@
                                           WAIT_LOCK)
 #define HEAD_UNLOCK() PyThread_release_lock(_PyRuntime.interpreters.mutex)
 
-static void _PyGILState_NoteThreadState(PyThreadState* tstate);
+/* Forward declaration */
+static void _PyGILState_NoteThreadState(
+    struct _gilstate_runtime_state *gilstate, PyThreadState* tstate);
 
 _PyInitError
 _PyInterpreterState_Enable(_PyRuntimeState *runtime)
@@ -487,71 +489,74 @@
 new_threadstate(PyInterpreterState *interp, int init)
 {
     PyThreadState *tstate = (PyThreadState *)PyMem_RawMalloc(sizeof(PyThreadState));
-
-    if (_PyThreadState_GetFrame == NULL)
-        _PyThreadState_GetFrame = threadstate_getframe;
-
-    if (tstate != NULL) {
-        tstate->interp = interp;
-
-        tstate->frame = NULL;
-        tstate->recursion_depth = 0;
-        tstate->overflowed = 0;
-        tstate->recursion_critical = 0;
-        tstate->stackcheck_counter = 0;
-        tstate->tracing = 0;
-        tstate->use_tracing = 0;
-        tstate->gilstate_counter = 0;
-        tstate->async_exc = NULL;
-        tstate->thread_id = PyThread_get_thread_ident();
-
-        tstate->dict = NULL;
-
-        tstate->curexc_type = NULL;
-        tstate->curexc_value = NULL;
-        tstate->curexc_traceback = NULL;
-
-        tstate->exc_state.exc_type = NULL;
-        tstate->exc_state.exc_value = NULL;
-        tstate->exc_state.exc_traceback = NULL;
-        tstate->exc_state.previous_item = NULL;
-        tstate->exc_info = &tstate->exc_state;
-
-        tstate->c_profilefunc = NULL;
-        tstate->c_tracefunc = NULL;
-        tstate->c_profileobj = NULL;
-        tstate->c_traceobj = NULL;
-
-        tstate->trash_delete_nesting = 0;
-        tstate->trash_delete_later = NULL;
-        tstate->on_delete = NULL;
-        tstate->on_delete_data = NULL;
-
-        tstate->coroutine_origin_tracking_depth = 0;
-
-        tstate->coroutine_wrapper = NULL;
-        tstate->in_coroutine_wrapper = 0;
-
-        tstate->async_gen_firstiter = NULL;
-        tstate->async_gen_finalizer = NULL;
-
-        tstate->context = NULL;
-        tstate->context_ver = 1;
-
-        tstate->id = ++interp->tstate_next_unique_id;
-
-        if (init)
-            _PyThreadState_Init(tstate);
-
-        HEAD_LOCK();
-        tstate->prev = NULL;
-        tstate->next = interp->tstate_head;
-        if (tstate->next)
-            tstate->next->prev = tstate;
-        interp->tstate_head = tstate;
-        HEAD_UNLOCK();
+    if (tstate == NULL) {
+        return NULL;
     }
 
+    if (_PyThreadState_GetFrame == NULL) {
+        _PyThreadState_GetFrame = threadstate_getframe;
+    }
+
+    tstate->interp = interp;
+
+    tstate->frame = NULL;
+    tstate->recursion_depth = 0;
+    tstate->overflowed = 0;
+    tstate->recursion_critical = 0;
+    tstate->stackcheck_counter = 0;
+    tstate->tracing = 0;
+    tstate->use_tracing = 0;
+    tstate->gilstate_counter = 0;
+    tstate->async_exc = NULL;
+    tstate->thread_id = PyThread_get_thread_ident();
+
+    tstate->dict = NULL;
+
+    tstate->curexc_type = NULL;
+    tstate->curexc_value = NULL;
+    tstate->curexc_traceback = NULL;
+
+    tstate->exc_state.exc_type = NULL;
+    tstate->exc_state.exc_value = NULL;
+    tstate->exc_state.exc_traceback = NULL;
+    tstate->exc_state.previous_item = NULL;
+    tstate->exc_info = &tstate->exc_state;
+
+    tstate->c_profilefunc = NULL;
+    tstate->c_tracefunc = NULL;
+    tstate->c_profileobj = NULL;
+    tstate->c_traceobj = NULL;
+
+    tstate->trash_delete_nesting = 0;
+    tstate->trash_delete_later = NULL;
+    tstate->on_delete = NULL;
+    tstate->on_delete_data = NULL;
+
+    tstate->coroutine_origin_tracking_depth = 0;
+
+    tstate->coroutine_wrapper = NULL;
+    tstate->in_coroutine_wrapper = 0;
+
+    tstate->async_gen_firstiter = NULL;
+    tstate->async_gen_finalizer = NULL;
+
+    tstate->context = NULL;
+    tstate->context_ver = 1;
+
+    tstate->id = ++interp->tstate_next_unique_id;
+
+    if (init) {
+        _PyThreadState_Init(&_PyRuntime, tstate);
+    }
+
+    HEAD_LOCK();
+    tstate->prev = NULL;
+    tstate->next = interp->tstate_head;
+    if (tstate->next)
+        tstate->next->prev = tstate;
+    interp->tstate_head = tstate;
+    HEAD_UNLOCK();
+
     return tstate;
 }
 
@@ -568,9 +573,9 @@
 }
 
 void
-_PyThreadState_Init(PyThreadState *tstate)
+_PyThreadState_Init(_PyRuntimeState *runtime, PyThreadState *tstate)
 {
-    _PyGILState_NoteThreadState(tstate);
+    _PyGILState_NoteThreadState(&runtime->gilstate, tstate);
 }
 
 PyObject*
@@ -1037,17 +1042,23 @@
    Py_Initialize/Py_FinalizeEx
 */
 void
-_PyGILState_Init(PyInterpreterState *i, PyThreadState *t)
+_PyGILState_Init(PyInterpreterState *interp, PyThreadState *tstate)
 {
-    assert(i && t); /* must init with valid states */
-    if (PyThread_tss_create(&_PyRuntime.gilstate.autoTSSkey) != 0) {
+    /* must init with valid states */
+    assert(interp != NULL);
+    assert(tstate != NULL);
+
+    _PyRuntimeState *runtime = &_PyRuntime;
+    struct _gilstate_runtime_state *gilstate = &runtime->gilstate;
+
+    if (PyThread_tss_create(&gilstate->autoTSSkey) != 0) {
         Py_FatalError("Could not allocate TSS entry");
     }
-    _PyRuntime.gilstate.autoInterpreterState = i;
-    assert(PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey) == NULL);
-    assert(t->gilstate_counter == 0);
+    gilstate->autoInterpreterState = interp;
+    assert(PyThread_tss_get(&gilstate->autoTSSkey) == NULL);
+    assert(tstate->gilstate_counter == 0);
 
-    _PyGILState_NoteThreadState(t);
+    _PyGILState_NoteThreadState(gilstate, tstate);
 }
 
 PyInterpreterState *
@@ -1104,13 +1115,14 @@
    a better fix for SF bug #1010677 than the first one attempted).
 */
 static void
-_PyGILState_NoteThreadState(PyThreadState* tstate)
+_PyGILState_NoteThreadState(struct _gilstate_runtime_state *gilstate, PyThreadState* tstate)
 {
     /* If autoTSSkey isn't initialized, this must be the very first
        threadstate created in Py_Initialize().  Don't do anything for now
        (we'll be back here when _PyGILState_Init is called). */
-    if (!_PyRuntime.gilstate.autoInterpreterState)
+    if (!gilstate->autoInterpreterState) {
         return;
+    }
 
     /* Stick the thread state for this thread in thread specific storage.
 
@@ -1124,10 +1136,8 @@
        The first thread state created for that given OS level thread will
        "win", which seems reasonable behaviour.
     */
-    if (PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey) == NULL) {
-        if ((PyThread_tss_set(&_PyRuntime.gilstate.autoTSSkey, (void *)tstate)
-             ) != 0)
-        {
+    if (PyThread_tss_get(&gilstate->autoTSSkey) == NULL) {
+        if ((PyThread_tss_set(&gilstate->autoTSSkey, (void *)tstate)) != 0) {
             Py_FatalError("Couldn't create autoTSSkey mapping");
         }
     }