|
1 |
| -# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. |
| 1 | +# Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. |
2 | 2 | # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
3 | 3 | #
|
4 | 4 | # The Universal Permissive License (UPL), Version 1.0
|
|
36 | 36 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
37 | 37 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
38 | 38 | # SOFTWARE.
|
| 39 | +import threading |
39 | 40 |
|
40 |
| -from . import CPyExtTestCase, CPyExtFunction, unhandled_error_compare |
| 41 | +from . import CPyExtTestCase, CPyExtFunction, unhandled_error_compare, CPyExtType |
41 | 42 |
|
42 | 43 | __dir__ = __file__.rpartition("/")[0]
|
43 | 44 |
|
@@ -83,3 +84,43 @@ def compile_module(self, name):
|
83 | 84 | callfunction="test_PyThread_tss_functions",
|
84 | 85 | cmpfunc=unhandled_error_compare
|
85 | 86 | )
|
| 87 | + |
| 88 | + |
| 89 | +class TestNativeThread: |
| 90 | + def test_register_new_thread(self): |
| 91 | + TestThread = CPyExtType( |
| 92 | + name="TestThread", |
| 93 | + includes="#include <pthread.h>", |
| 94 | + code=r''' |
| 95 | + void* thread_entrypoint(void* arg) { |
| 96 | + PyObject* callable = (PyObject*)arg; |
| 97 | + PyGILState_STATE gstate; |
| 98 | + gstate = PyGILState_Ensure(); |
| 99 | + if (!PyObject_CallNoArgs(callable)) { |
| 100 | + PyErr_WriteUnraisable(callable); |
| 101 | + } |
| 102 | + PyGILState_Release(gstate); |
| 103 | + return NULL; |
| 104 | + } |
| 105 | + PyObject* run_in_thread(PyObject* self, PyObject* callable) { |
| 106 | + Py_BEGIN_ALLOW_THREADS; |
| 107 | + pthread_t thread; |
| 108 | + pthread_create(&thread, NULL, thread_entrypoint, callable); |
| 109 | + pthread_join(thread, NULL); |
| 110 | + Py_END_ALLOW_THREADS; |
| 111 | + Py_RETURN_NONE; |
| 112 | + } |
| 113 | + ''', |
| 114 | + tp_methods='{"run_in_thread", (PyCFunction)run_in_thread, METH_O | METH_STATIC, ""}' |
| 115 | + ) |
| 116 | + |
| 117 | + thread = None |
| 118 | + |
| 119 | + def callable(): |
| 120 | + nonlocal thread |
| 121 | + thread = threading.current_thread() |
| 122 | + |
| 123 | + TestThread.run_in_thread(callable) |
| 124 | + |
| 125 | + assert thread |
| 126 | + assert thread is not threading.current_thread() |
0 commit comments