美文网首页
大师兄的Python源码学习笔记(二十九): 运行环境初始化(一

大师兄的Python源码学习笔记(二十九): 运行环境初始化(一

作者: superkmi | 来源:发表于2021-08-20 14:36 被阅读0次

大师兄的Python源码学习笔记(二十八): 虚拟机中的类机制(七)
大师兄的Python源码学习笔记(三十): 运行环境初始化(二)

一、线程环境初始化

1. 线程模型回顾
  • Python启动后,真正有意义的初始化动作是从Py_Initialize开始的:
Python\pylifecycle.c

void
Py_Initialize(void)
{
    Py_InitializeEx(1);
}
  • 其中仅有一个函数Py_InitializeEx被调用,它完成的一个重要工作就是加载多个基础module,如:__builtin__,sys等
  • 此外,它还会完成Python类型系统异常系统的初始化,以及许多其它工作。
Python\pylifecycle.c

void
Py_InitializeEx(int install_sigs)
{
    if (_PyRuntime.initialized) {
        /* bpo-33932: Calling Py_Initialize() twice does nothing. */
        return;
    }

    _PyInitError err;
    _PyCoreConfig config = _PyCoreConfig_INIT;
    config.install_signal_handlers = install_sigs;

    err = _Py_InitializeFromConfig(&config);
    _PyCoreConfig_Clear(&config);

    if (_Py_INIT_FAILED(err)) {
        _Py_FatalInitError(err);
    }
}
2. 初始化线程环境
  • 在Win32平台,当执行一个可执行文件时,操作系统会先创建一个进程内核对象。
  • 在Python中也是如此,它会调用PyInterpreterState_New创建一个PyInterpreterState对象(进程对象)
Python\pystate.c

PyInterpreterState *
PyInterpreterState_New(void)
{
    PyInterpreterState *interp = (PyInterpreterState *)
                                 PyMem_RawMalloc(sizeof(PyInterpreterState));

    if (interp == NULL) {
        return NULL;
    }

    interp->id_refcount = -1;
    interp->id_mutex = NULL;
    interp->modules = NULL;
    interp->modules_by_index = NULL;
    interp->sysdict = NULL;
    interp->builtins = NULL;
    interp->builtins_copy = NULL;
    interp->tstate_head = NULL;
    interp->check_interval = 100;
    interp->num_threads = 0;
    interp->pythread_stacksize = 0;
    interp->codec_search_path = NULL;
    interp->codec_search_cache = NULL;
    interp->codec_error_registry = NULL;
    interp->codecs_initialized = 0;
    interp->fscodec_initialized = 0;
    interp->core_config = _PyCoreConfig_INIT;
    interp->config = _PyMainInterpreterConfig_INIT;
    interp->importlib = NULL;
    interp->import_func = NULL;
    interp->eval_frame = _PyEval_EvalFrameDefault;
    interp->co_extra_user_count = 0;
#ifdef HAVE_DLOPEN
#if HAVE_DECL_RTLD_NOW
    interp->dlopenflags = RTLD_NOW;
#else
    interp->dlopenflags = RTLD_LAZY;
#endif
#endif
#ifdef HAVE_FORK
    interp->before_forkers = NULL;
    interp->after_forkers_parent = NULL;
    interp->after_forkers_child = NULL;
#endif
    interp->pyexitfunc = NULL;
    interp->pyexitmodule = NULL;

    HEAD_LOCK();
    interp->next = _PyRuntime.interpreters.head;
    if (_PyRuntime.interpreters.main == NULL) {
        _PyRuntime.interpreters.main = interp;
    }
    _PyRuntime.interpreters.head = interp;
    if (_PyRuntime.interpreters.next_id < 0) {
        /* overflow or Py_Initialize() not called! */
        PyErr_SetString(PyExc_RuntimeError,
                        "failed to get an interpreter ID");
        /* XXX deallocate! */
        interp = NULL;
    } else {
        interp->id = _PyRuntime.interpreters.next_id;
        _PyRuntime.interpreters.next_id += 1;
    }
    HEAD_UNLOCK();

    interp->tstate_next_unique_id = 0;

    return interp;
}
  • 在Python的运行时环境属性会通过_PyRuntimeState对象管理:
Include\internal\pystate.h

typedef struct pyruntimestate {
    int initialized;
    int core_initialized;
    PyThreadState *finalizing;

    struct pyinterpreters {
        PyThread_type_lock mutex;
        PyInterpreterState *head;
        PyInterpreterState *main;
        /* _next_interp_id is an auto-numbered sequence of small
           integers.  It gets initialized in _PyInterpreterState_Init(),
           which is called in Py_Initialize(), and used in
           PyInterpreterState_New().  A negative interpreter ID
           indicates an error occurred.  The main interpreter will
           always have an ID of 0.  Overflow results in a RuntimeError.
           If that becomes a problem later then we can adjust, e.g. by
           using a Python int. */
        int64_t next_id;
    } interpreters;

#define NEXITFUNCS 32
    void (*exitfuncs[NEXITFUNCS])(void);
    int nexitfuncs;

    struct _gc_runtime_state gc;
    struct _warnings_runtime_state warnings;
    struct _ceval_runtime_state ceval;
    struct _gilstate_runtime_state gilstate;

    // XXX Consolidate globals found via the check-c-globals script.
} _PyRuntimeState;
  • 结合上面的代码,我们可以发现_PyRuntime对象实际在管理一个PyInterpreterState对象的链表,而表头正是_PyRuntime.interpreters.head
  • 这其实正是Python对操作系统上多进程的模拟。
  • 紧接着,Python会立即调用PyThreadState_New,创建一个PyThreadState对象(线程对象)
Python\pystate.c

PyThreadState *
PyThreadState_New(PyInterpreterState *interp)
{
    return new_threadstate(interp, 1);
}
Python\pystate.c

static PyThreadState *
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();
    }

    return tstate;
}
  • PyInterpreterState_New类似,new_threadstate通过interp.tstate_head管理PyThreadState对象链表,这与Python中的多线程实现有关。
  • 观察PyThreadState对象:
Include\pystate.h

typedef struct _ts {
    /* See Python/ceval.c for comments explaining most fields */

    struct _ts *prev;
    struct _ts *next;
    PyInterpreterState *interp;

    struct _frame *frame;
    int recursion_depth;
    ... ...
} PyThreadState;
  • 其中设置了从线程中获得函数调用栈的方法,所谓函数调用栈也就是PyFrameObject对象链表。
  • 到这里,PyInterpreterState对象PyThreadState对象建立起了联系,也就是进程和线程建立起了联系。
  • 在Python运行是环境中,有一个全局变量_PyThreadState_Current,用来维护当前活动的线程对应的PyThreadState对象:
Include\pystate.h

#  define _PyThreadState_Current _PyRuntime.gilstate.tstate_current
  • 可以看出_PyThreadState_Current对应_PyRuntime.gilstate.tstate_current
  • Python通过调用PyThreadState_Swap设置_PyThreadState_Current:
Python\pystate.c

PyThreadState *
PyThreadState_Swap(PyThreadState *newts)
{
    PyThreadState *oldts = GET_TSTATE();

    SET_TSTATE(newts);
    /* It should not be possible for more than one thread state
       to be used for a thread.  Check this the best we can in debug
       builds.
    */
#if defined(Py_DEBUG)
    if (newts) {
        /* This can be called from PyEval_RestoreThread(). Similar
           to it, we need to ensure errno doesn't change.
        */
        int err = errno;
        PyThreadState *check = PyGILState_GetThisThreadState();
        if (check && check->interp == newts->interp && check != newts)
            Py_FatalError("Invalid thread state for this thread");
        errno = err;
    }
#endif
    return oldts;
}
  • 接着,Python的初始化动作开始转向Python类型系统的初始化,这个转折是从Py_InitializeEx中调用_Py_ReadyTypes时开始的:
Python\pylifecycle.c

void
Py_InitializeEx(int install_sigs)
{
   ... ...
    err = _Py_InitializeFromConfig(&config);
    ... ...
}
Python\pylifecycle.c

_PyInitError
_Py_InitializeFromConfig(const _PyCoreConfig *config)
{
    _Py_Initialize_ReadEnvVarsNoAlloc();

    PyInterpreterState *interp;
    _PyInitError err;
    err = _Py_InitializeCore(&interp, config);
    ... ...
}
Python\pylifecycle.c

_PyInitError
_Py_InitializeCore(PyInterpreterState **interp_p,
                   const _PyCoreConfig *src_config)
{
    ... ...
    _PyInitError err;
    ... ...
    err = _Py_InitializeCore_impl(interp_p, &config);
    ... ...
}
Python\pylifecycle.c

_PyInitError
_Py_InitializeCore_impl(PyInterpreterState **interp_p,
                        const _PyCoreConfig *core_config)
{
    PyInterpreterState *interp;
    _PyInitError err;

    ... ...

    _Py_ReadyTypes();
    ... ...
Python\pylifecycle.c

void
_Py_ReadyTypes(void)
{
    if (PyType_Ready(&PyBaseObject_Type) < 0)
        Py_FatalError("Can't initialize object type");

    if (PyType_Ready(&PyType_Type) < 0)
        Py_FatalError("Can't initialize type type");

    if (PyType_Ready(&_PyWeakref_RefType) < 0)
        Py_FatalError("Can't initialize weakref type");

    if (PyType_Ready(&_PyWeakref_CallableProxyType) < 0)
        Py_FatalError("Can't initialize callable weakref proxy type");

    ... ...
}

相关文章

网友评论

      本文标题:大师兄的Python源码学习笔记(二十九): 运行环境初始化(一

      本文链接:https://www.haomeiwen.com/subject/tfbgbltx.html