| 262 | static PyEventLoop getMainLoop(); |
| 263 | |
| 264 | struct Lock { |
| 265 | public: |
| 266 | explicit Lock() { |
| 267 | PyObject *asyncio = PyImport_ImportModule("asyncio"); |
| 268 | _queueIsEmpty = PyObject_CallMethod(asyncio, "Event", NULL); // _queueIsEmpty = asyncio.Event() |
| 269 | Py_DECREF(asyncio); |
| 270 | |
| 271 | // The flag should initially be set as the queue is initially empty |
| 272 | Py_XDECREF(PyObject_CallMethod(_queueIsEmpty, "set", NULL)); // _queueIsEmpty.set() |
| 273 | }; |
| 274 | ~Lock() { |
| 275 | Py_DECREF(_queueIsEmpty); |
| 276 | } |
| 277 | |
| 278 | /** |
| 279 | * @brief Increment the counter for the number of our job functions in the Python event-loop |
| 280 | */ |
| 281 | inline void incCounter() { |
| 282 | _counter++; |
| 283 | Py_XDECREF(PyObject_CallMethod(_queueIsEmpty, "clear", NULL)); // _queueIsEmpty.clear() |
| 284 | } |
| 285 | |
| 286 | /** |
| 287 | * @brief Decrement the counter for the number of our job functions in the Python event-loop |
| 288 | */ |
| 289 | inline void decCounter() { |
| 290 | _counter--; |
| 291 | if (_counter == 0) { // no job queueing |
| 292 | // Notify that the queue is empty and awake (unblock) the event-loop shield |
| 293 | Py_XDECREF(PyObject_CallMethod(_queueIsEmpty, "set", NULL)); // _queueIsEmpty.set() |
| 294 | } else if (_counter < 0) { // something went wrong |
| 295 | PyErr_SetString(PyExc_RuntimeError, "Event-loop job counter went below zero."); |
| 296 | } |
| 297 | } |
| 298 | |
| 299 | /** |
| 300 | * @brief An `asyncio.Event` instance to notify that there are no queued asynchronous jobs |
| 301 | * @see https://docs.python.org/3/library/asyncio-sync.html#asyncio.Event |
| 302 | */ |
| 303 | PyObject *_queueIsEmpty = nullptr; |
| 304 | protected: |
| 305 | std::atomic_int _counter = 0; |
| 306 | }; |
| 307 | |
| 308 | static inline PyEventLoop::Lock *_locker; |
| 309 |
nothing calls this directly
no outgoing calls
no test coverage detected