Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-85283: Add PyInterpreterState_IsMain() function#108577

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
vstinner wants to merge1 commit intopython:mainfromvstinner:interp_is_main

Conversation

vstinner
Copy link
Member

@vstinnervstinner commentedAug 28, 2023
edited by github-actionsbot
Loading

This function can be used to convert the syslog extension to the limited C API. The PyInterpreterState_Main() is not available in the limited C API.


📚 Documentation preview 📚:https://cpython-previews--108577.org.readthedocs.build/

sidba2003 reacted with heart emoji
@vstinner
Copy link
MemberAuthor

cc@ericsnowcurrently

Maybe the concept of "main interpreter" should be elaborate in the doc, since right now it's simply not documented or defined. I suppose that it's the only one which is allowed to register signal handlers?

Currently, the main interpreter has more features:

  • Can fork()
  • Has the "obmalloc" state (pymalloc)
  • Is responsible for init/clean global Python objects and other "global Python states", like static types and static built-ins, interned Unicode strings, GIL State, etc.
  • Can use PyOS_Readline()
  • Can import extensions which don't support sub-interpreters
  • Can call _PyPathConfig_UpdateGlobal()
  • Initialize_PyRuntime

I'm not sure about exec() and threads(), and these options:

if (config->use_main_obmalloc) {interp->feature_flags |=Py_RTFLAGS_USE_MAIN_OBMALLOC;    }elseif (!config->check_multi_interp_extensions) {/* The reason: PyModuleDef.m_base.m_copy leaks objects between           interpreters. */return_PyStatus_ERR("per-interpreter obmalloc does not support ""single-phase init extension modules");    }if (config->allow_fork) {interp->feature_flags |=Py_RTFLAGS_FORK;    }if (config->allow_exec) {interp->feature_flags |=Py_RTFLAGS_EXEC;    }// Note that fork+exec is always allowed.if (config->allow_threads) {interp->feature_flags |=Py_RTFLAGS_THREADS;    }if (config->allow_daemon_threads) {interp->feature_flags |=Py_RTFLAGS_DAEMON_THREADS;    }if (config->check_multi_interp_extensions) {interp->feature_flags |=Py_RTFLAGS_MULTI_INTERP_EXTENSIONS;    }

The alternative is to exposePyInterpreterState_Main() which gives the main interpreter. I'm not sure which API is the best.

In Python 3.13, I also added Py_IsFinalizing():https://docs.python.org/dev/c-api/init.html#c.Py_IsFinalizing

sidba2003 reacted with heart emoji

This function can be used to convert the syslog extension to thelimited C API. The PyInterpreterState_Main() is not available in thelimited C API.
@vstinnervstinner requested a review froma team as acode ownerAugust 28, 2023 17:24
@ericsnowcurrently
Copy link
Member

Maybe the concept of "main interpreter" should be elaborate in the doc, since right now it's simply not documented or defined.

Seehttps://docs.python.org/3.12/c-api/init.html#sub-interpreter-support.

The alternative is to exposePyInterpreterState_Main() which gives the main interpreter. I'm not sure which API is the best.

Having both would be fine.

@vstinner
Copy link
MemberAuthor

I would prefer to only add a single function to thelimited C API.

@encukou
Copy link
Member

encukou commentedAug 31, 2023
edited
Loading

Long-term, I don't think relying on “main”-ness is the right way.
In syslog, I guess only one interpreter can open the log, but it doesn'thave to be the main interpreter.

@vstinner
Copy link
MemberAuthor

Long-term, I don't think relying on “main”-ness is the right way.
In syslog, I guess only one interpreter can open the log, but it doesn't have to be the main interpreter.

For the specific case of the syslog module, please see issuegh-99127 and commit8bb2303.

@encukou
Copy link
Member

Yes. The current code makes an assumption that the “app” (that is, top-level code that sets up logging) lives in the main interpreter.
That's a fairly reasonable assumption at the moment, when the focus is on getting multiple interpreters working. But I'd rather not encourage relying on this assumption in the long term.

erlend-aasland reacted with thumbs up emoji

@vstinner
Copy link
MemberAuthor

Yes. The current code makes an assumption that the “app” (that is, top-level code that sets up logging) lives in the main interpreter. That's a fairly reasonable assumption at the moment, when the focus is on getting multiple interpreters working. But I'd rather not encourage relying on this assumption in the long term.

In Python, the main interpreter is special. It has special skills and using Python API behaves differently depending if the current interpreter is the main one or not. So IMO it makes sense to check if the current code is running the main interpreter or not.

I suggest to leave the syslog extension aside. It can make its own decisions and yes, it can change in the future :-)


Cython uses a differerent logic to handle PEP 489 "Multi-phase extension module initialization". It uses astatic PY_INT64_T main_interpreter_id = -1; variable which is initialized at the first call of__Pyx_check_single_interpreter().

But the problem is unrelated to checking if we are running the main interpreter or not.

//#if CYTHON_PEP489_MULTI_PHASE_INITstaticCYTHON_SMALL_CODEint__Pyx_check_single_interpreter(void) {#ifPY_VERSION_HEX >=0x030700A1staticPY_INT64_Tmain_interpreter_id=-1;PY_INT64_Tcurrent_id=PyInterpreterState_GetID(PyThreadState_Get()->interp);if (main_interpreter_id==-1) {main_interpreter_id=current_id;return (unlikely(current_id==-1)) ?-1 :0;    }elseif (unlikely(main_interpreter_id!=current_id))#elsestaticPyInterpreterState*main_interpreter=NULL;PyInterpreterState*current_interpreter=PyThreadState_Get()->interp;if (!main_interpreter) {main_interpreter=current_interpreter;    }elseif (unlikely(main_interpreter!=current_interpreter))#endif    {PyErr_SetString(PyExc_ImportError,"Interpreter change detected - this module can only be loaded into one interpreter per process.");return-1;    }return0;}

@vstinner
Copy link
MemberAuthor

Usage of the different existing APIs to check for the main intrepreter in PyPI top 5,000 projects.

Affected projects (9):

  • billiard (4.1.0)
  • catboost (1.2)
  • fastobo (0.12.2)
  • multiprocess (0.70.14)
  • numpy (1.25.0)
  • orjson (3.9.1)
  • psycopg2 (2.9.6)
  • psycopg2-binary (2.9.6)
  • tensorstore (0.1.40)

PyO3 binding has a comment about the lack of limited C API for this:

pyo3-ffi/src/intrcheck.rs: // skipped non-limited _PyOS_IsMainThread

tensorstore also has a comment about _PyOS_IsMainThread():

/// We can't use `_PyOS_IsMainThread()` because that requires the GIL on some

All matches:

PYPI-2023-07-04/billiard-4.1.0.tar.gz:billiard-4.1.0/Modules/_billiard/win32_functions.c:if (!wait_flag&&_PyOS_IsMainThread()) {PYPI-2023-07-04/fastobo-0.12.2.tar.gz:fastobo-0.12.2/crates/pyo3-ffi/src/cpython/pystate.rs:pubfnPyInterpreterState_Main()->*mutPyInterpreterState;PYPI-2023-07-04/fastobo-0.12.2.tar.gz:fastobo-0.12.2/crates/pyo3-ffi/src/intrcheck.rs:// skipped non-limited _PyOS_IsMainThreadPYPI-2023-07-04/catboost-1.2.tar.gz:catboost-1.2/catboost_all_src/contrib/python/numpy/py3/numpy/core/src/multiarray/multiarraymodule.c:if (PyThreadState_Get()->interp!=PyInterpreterState_Main()) {PYPI-2023-07-04/numpy-1.25.0.tar.gz:numpy-1.25.0/numpy/core/src/multiarray/multiarraymodule.c:if (PyThreadState_Get()->interp!=PyInterpreterState_Main()) {PYPI-2023-07-04/orjson-3.9.1.tar.gz:orjson-3.9.1/include/cargo/pyo3-ffi-0.19.0/src/cpython/pystate.rs:pubfnPyInterpreterState_Main()->*mutPyInterpreterState;PYPI-2023-07-04/orjson-3.9.1.tar.gz:orjson-3.9.1/include/cargo/pyo3-ffi-0.19.0/src/intrcheck.rs:// skipped non-limited _PyOS_IsMainThreadPYPI-2023-07-04/psycopg2-2.9.6.tar.gz:psycopg2-2.9.6/psycopg/utils.c:return_PyInterpreterState_Get()==PyInterpreterState_Main();PYPI-2023-07-04/psycopg2-binary-2.9.6.tar.gz:psycopg2-binary-2.9.6/psycopg/utils.c:return_PyInterpreterState_Get()==PyInterpreterState_Main();PYPI-2023-07-04/multiprocess-0.70.14.tar.gz:multiprocess-0.70.14/py3.10/Modules/_multiprocess/semaphore.c:if (_PyOS_IsMainThread()) {PYPI-2023-07-04/multiprocess-0.70.14.tar.gz:multiprocess-0.70.14/py3.11/Modules/_multiprocess/semaphore.c:if (_PyOS_IsMainThread()) {PYPI-2023-07-04/multiprocess-0.70.14.tar.gz:multiprocess-0.70.14/py3.7/Modules/_multiprocess/semaphore.c:if (_PyOS_IsMainThread()) {PYPI-2023-07-04/multiprocess-0.70.14.tar.gz:multiprocess-0.70.14/py3.8/Modules/_multiprocess/semaphore.c:if (_PyOS_IsMainThread()) {PYPI-2023-07-04/multiprocess-0.70.14.tar.gz:multiprocess-0.70.14/py3.9/Modules/_multiprocess/semaphore.c:if (_PyOS_IsMainThread()) {PYPI-2023-07-04/tensorstore-0.1.40.tar.gz:tensorstore-0.1.40/python/tensorstore/gil_safe.cc:/// We can't use `_PyOS_IsMainThread()` because that requires the GIL on some

@encukou
Copy link
Member

Cython uses a differerent logic to handle PEP 489 "Multi-phase extension module initialization". It uses a static PY_INT64_T main_interpreter_id = -1; variable which is initialized at the first call of __Pyx_check_single_interpreter().

But the problem is unrelated to checking if we are running the main interpreter or not.

IMO, this is along the lines of whatsyslog should do. It doesn't need the special skills of the main interpreter -- it only requires that different interpreters don't interfere with each other.
(Also,syslog.closelog can reset thatint back to -1.)

@vstinner
Copy link
MemberAuthor

IMO, this is along the lines of what syslog should do. It doesn't need the special skills of the main interpreter -- it only requires that different interpreters don't interfere with each other.

Do you want to propose an API to implement such check? How would the API look like?

@vstinner
Copy link
MemberAuthor

Using the limited C API in stdlib C extensions is somehow on hold, and it became unclear to me if this function is the right want to handle sub-interpreters: see issuegh-109857. So I prefer close this PR for now.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@encukouencukouAwaiting requested review from encukouencukou is a code owner

Assignees
No one assigned
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

4 participants
@vstinner@ericsnowcurrently@encukou@bedevere-bot

[8]ページ先頭

©2009-2025 Movatter.jp