Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
PyModule.cpp297 linesDownload Raw Back to greenlet
1#ifndef PY_MODULE_CPP
2#define PY_MODULE_CPP
3
4#include "greenlet_internal.hpp"
5
6
7#include "TGreenletGlobals.cpp"
8#include "TMainGreenlet.cpp"
9#include "TThreadStateDestroy.cpp"
10
11using greenlet::LockGuard;
12using greenlet::ThreadState;
13
14#ifdef __clang__
15#    pragma clang diagnostic push
16#    pragma clang diagnostic ignored "-Wunused-function"
17#    pragma clang diagnostic ignored "-Wunused-variable"
18#endif
19
20
21PyDoc_STRVAR(mod_getcurrent_doc,
22             "getcurrent() -> greenlet\n"
23             "\n"
24             "Returns the current greenlet (i.e. the one which called this "
25             "function).\n");
26
27static PyObject*
28mod_getcurrent(PyObject* UNUSED(module))
29{
30    if (greenlet::IsShuttingDown()) {
31        Py_RETURN_NONE;
32    }
33    return GET_THREAD_STATE().state().get_current().relinquish_ownership_o();
34}
35
36PyDoc_STRVAR(mod_settrace_doc,
37             "settrace(callback) -> object\n"
38             "\n"
39             "Sets a new tracing function and returns the previous one.\n");
40static PyObject*
41mod_settrace(PyObject* UNUSED(module), PyObject* args)
42{
43    PyArgParseParam tracefunc;
44    if (!PyArg_ParseTuple(args, "O", &tracefunc)) {
45        return NULL;
46    }
47    ThreadState& state = GET_THREAD_STATE();
48    OwnedObject previous = state.get_tracefunc();
49    if (!previous) {
50        previous = Py_None;
51    }
52
53    state.set_tracefunc(tracefunc);
54
55    return previous.relinquish_ownership();
56}
57
58PyDoc_STRVAR(mod_gettrace_doc,
59             "gettrace() -> object\n"
60             "\n"
61             "Returns the currently set tracing function, or None.\n");
62
63static PyObject*
64mod_gettrace(PyObject* UNUSED(module))
65{
66    OwnedObject tracefunc = GET_THREAD_STATE().state().get_tracefunc();
67    if (!tracefunc) {
68        tracefunc = Py_None;
69    }
70    return tracefunc.relinquish_ownership();
71}
72
73
74
75PyDoc_STRVAR(mod_set_thread_local_doc,
76             "set_thread_local(key, value) -> None\n"
77             "\n"
78             "Set a value in the current thread-local dictionary. Debugging only.\n");
79
80static PyObject*
81mod_set_thread_local(PyObject* UNUSED(module), PyObject* args)
82{
83    PyArgParseParam key;
84    PyArgParseParam value;
85    PyObject* result = NULL;
86
87    if (PyArg_UnpackTuple(args, "set_thread_local", 2, 2, &key, &value)) {
88        if(PyDict_SetItem(
89                          PyThreadState_GetDict(), // borrow
90                          key,
91                          value) == 0 ) {
92            // success
93            Py_INCREF(Py_None);
94            result = Py_None;
95        }
96    }
97    return result;
98}
99
100PyDoc_STRVAR(mod_get_pending_cleanup_count_doc,
101             "get_pending_cleanup_count() -> Integer\n"
102             "\n"
103             "Get the number of greenlet cleanup operations pending. Testing only.\n");
104
105
106static PyObject*
107mod_get_pending_cleanup_count(PyObject* UNUSED(module))
108{
109    LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock);
110    return PyLong_FromSize_t(mod_globs->thread_states_to_destroy.size());
111}
112
113PyDoc_STRVAR(mod_get_total_main_greenlets_doc,
114             "get_total_main_greenlets() -> Integer\n"
115             "\n"
116             "Quickly return the number of main greenlets that exist. Testing only.\n");
117
118static PyObject*
119mod_get_total_main_greenlets(PyObject* UNUSED(module))
120{
121    return PyLong_FromSize_t(G_TOTAL_MAIN_GREENLETS);
122}
123
124
125
126PyDoc_STRVAR(mod_get_clocks_used_doing_optional_cleanup_doc,
127             "get_clocks_used_doing_optional_cleanup() -> Integer\n"
128             "\n"
129             "Get the number of clock ticks the program has used doing optional "
130             "greenlet cleanup.\n"
131             "Beginning in greenlet 2.0, greenlet tries to find and dispose of greenlets\n"
132             "that leaked after a thread exited. This requires invoking Python's garbage collector,\n"
133             "which may have a performance cost proportional to the number of live objects.\n"
134             "This function returns the amount of processor time\n"
135             "greenlet has used to do this. In programs that run with very large amounts of live\n"
136             "objects, this metric can be used to decide whether the cost of doing this cleanup\n"
137             "is worth the memory leak being corrected. If not, you can disable the cleanup\n"
138             "using ``enable_optional_cleanup(False)``.\n"
139             "The units are arbitrary and can only be compared to themselves (similarly to ``time.clock()``);\n"
140             "for example, to see how it scales with your heap. You can attempt to convert them into seconds\n"
141             "by dividing by the value of CLOCKS_PER_SEC."
142             "If cleanup has been disabled, returns None."
143             "\n"
144             "This is an implementation specific, provisional API. It may be changed or removed\n"
145             "in the future.\n"
146             ".. versionadded:: 2.0"
147             );
148static PyObject*
149mod_get_clocks_used_doing_optional_cleanup(PyObject* UNUSED(module))
150{
151    std::clock_t clocks = ThreadState::clocks_used_doing_gc();
152
153    if (clocks == std::clock_t(-1)) {
154        Py_RETURN_NONE;
155    }
156    // This might not actually work on some implementations; clock_t
157    // is an opaque type.
158    return PyLong_FromSsize_t(clocks);
159}
160
161PyDoc_STRVAR(mod_enable_optional_cleanup_doc,
162             "mod_enable_optional_cleanup(bool) -> None\n"
163             "\n"
164             "Enable or disable optional cleanup operations.\n"
165             "See ``get_clocks_used_doing_optional_cleanup()`` for details.\n"
166             );
167static PyObject*
168mod_enable_optional_cleanup(PyObject* UNUSED(module), PyObject* flag)
169{
170    int is_true = PyObject_IsTrue(flag);
171    if (is_true == -1) {
172        return nullptr;
173    }
174
175    if (is_true) {
176        std::clock_t clocks = ThreadState::clocks_used_doing_gc();
177        // If we already have a value, we don't want to lose it.
178        if (clocks == std::clock_t(-1)) {
179            ThreadState::set_clocks_used_doing_gc(0);
180        }
181    }
182    else {
183        ThreadState::set_clocks_used_doing_gc(std::clock_t(-1));
184    }
185    Py_RETURN_NONE;
186}
187
188
189
190
191#if !GREENLET_PY313
192PyDoc_STRVAR(mod_get_tstate_trash_delete_nesting_doc,
193             "get_tstate_trash_delete_nesting() -> Integer\n"
194             "\n"
195             "Return the 'trash can' nesting level. Testing only.\n");
196static PyObject*
197mod_get_tstate_trash_delete_nesting(PyObject* UNUSED(module))
198{
199    PyThreadState* tstate = PyThreadState_GET();
200
201#if GREENLET_PY312
202    return PyLong_FromLong(tstate->trash.delete_nesting);
203#else
204    return PyLong_FromLong(tstate->trash_delete_nesting);
205#endif
206}
207#endif
208
209
210
211
212static PyMethodDef GreenMethods[] = {
213    {
214      .ml_name="getcurrent",
215      .ml_meth=(PyCFunction)mod_getcurrent,
216      .ml_flags=METH_NOARGS,
217      .ml_doc=mod_getcurrent_doc
218    },
219    {
220      .ml_name="settrace",
221      .ml_meth=(PyCFunction)mod_settrace,
222      .ml_flags=METH_VARARGS,
223      .ml_doc=mod_settrace_doc
224    },
225    {
226      .ml_name="gettrace",
227      .ml_meth=(PyCFunction)mod_gettrace,
228      .ml_flags=METH_NOARGS,
229      .ml_doc=mod_gettrace_doc
230    },
231    {
232      .ml_name="set_thread_local",
233      .ml_meth=(PyCFunction)mod_set_thread_local,
234      .ml_flags=METH_VARARGS,
235      .ml_doc=mod_set_thread_local_doc
236    },
237    {
238      .ml_name="get_pending_cleanup_count",
239      .ml_meth=(PyCFunction)mod_get_pending_cleanup_count,
240      .ml_flags=METH_NOARGS,
241      .ml_doc=mod_get_pending_cleanup_count_doc
242    },
243    {
244      .ml_name="get_total_main_greenlets",
245      .ml_meth=(PyCFunction)mod_get_total_main_greenlets,
246      .ml_flags=METH_NOARGS,
247      .ml_doc=mod_get_total_main_greenlets_doc
248    },
249    {
250      .ml_name="get_clocks_used_doing_optional_cleanup",
251      .ml_meth=(PyCFunction)mod_get_clocks_used_doing_optional_cleanup,
252      .ml_flags=METH_NOARGS,
253      .ml_doc=mod_get_clocks_used_doing_optional_cleanup_doc
254    },
255    {
256      .ml_name="enable_optional_cleanup",
257      .ml_meth=(PyCFunction)mod_enable_optional_cleanup,
258      .ml_flags=METH_O,
259      .ml_doc=mod_enable_optional_cleanup_doc
260    },
261#if !GREENLET_PY313
262    {
263      .ml_name="get_tstate_trash_delete_nesting",
264      .ml_meth=(PyCFunction)mod_get_tstate_trash_delete_nesting,
265      .ml_flags=METH_NOARGS,
266      .ml_doc=mod_get_tstate_trash_delete_nesting_doc
267    },
268#endif
269    {.ml_name=NULL, .ml_meth=NULL} /* Sentinel */
270};
271
272static const char* const copy_on_greentype[] = {
273    "getcurrent",
274    "error",
275    "GreenletExit",
276    "settrace",
277    "gettrace",
278    NULL
279};
280
281static struct PyModuleDef greenlet_module_def = {
282    .m_base=PyModuleDef_HEAD_INIT,
283    .m_name="greenlet._greenlet",
284    .m_doc=NULL,
285    .m_size=-1,
286    .m_methods=GreenMethods,
287};
288
289
290#endif
291
292#ifdef __clang__
293#    pragma clang diagnostic pop
294#elif defined(__GNUC__)
295#    pragma GCC diagnostic pop
296#endif
297 
codekingpro/portable-devtools · Team Ai