Skip to content

Commit f180939

Browse files
authored
Merge pull request #316 from Distributive-Network/Xmader/fix/setInterval-unref
HOTFIX: `.unref()` not working on `setInterval` timers
2 parents 48156b3 + 30f3f0c commit f180939

File tree

4 files changed

+17
-4
lines changed

4 files changed

+17
-4
lines changed

src/JobQueue.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ bool sendJobToMainLoop(PyObject *pyFunc) {
114114

115115
PyGILState_Release(gstate);
116116
return true;
117-
}
117+
}
118118

119119
void JobQueue::queueFinalizationRegistryCallback(JSFunction *callback) {
120120
mozilla::Unused << finalizationRegistryCallbacks->append(callback);

src/PyEventLoop.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ static PyObject *_enqueueWithDelay(PyObject *_loop, PyEventLoop::AsyncHandle::id
8080

8181
auto handle = PyEventLoop::AsyncHandle::fromId(handleId);
8282
Py_XDECREF(handle->swap(asyncHandle));
83-
handle->addRef();
8483

8584
return asyncHandle;
8685
}
@@ -90,6 +89,8 @@ PyEventLoop::AsyncHandle::id_t PyEventLoop::enqueueWithDelay(PyObject *jobFn, do
9089
if (!_enqueueWithDelay(_loop, handleId, jobFn, delaySeconds, repeat)) {
9190
PyErr_Print(); // RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one
9291
}
92+
auto handle = PyEventLoop::AsyncHandle::fromId(handleId);
93+
handle->addRef();
9394
return handleId;
9495
}
9596

src/internalBinding/utils.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @file utils.cc
33
* @author Tom Tang ([email protected])
44
* @brief Implement functions in `internalBinding("utils")`
5-
*
5+
*
66
* @copyright Copyright (c) 2023 Distributive Corp.
77
*/
88

tests/python/test_event_loop.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import pythonmonkey as pm
33
import asyncio
44

5-
def test_timers_unref():
5+
def test_setTimeout_unref():
66
async def async_fn():
77
obj = {'val': 0}
88
pm.eval("""(obj) => {
@@ -17,6 +17,18 @@ async def async_fn():
1717
return True
1818
assert asyncio.run(async_fn())
1919

20+
def test_setInterval_unref():
21+
async def async_fn():
22+
obj = {'val': 0}
23+
pm.eval("""(obj) => {
24+
setInterval(()=>{ obj.val++ }, 200).unref()
25+
setTimeout(()=>{ }, 500)
26+
}""")(obj)
27+
await pm.wait() # It should stop after the setTimeout timer's 500ms.
28+
assert obj['val'] == 2 # The setInterval timer should only run twice (500 // 200 == 2)
29+
return True
30+
assert asyncio.run(async_fn())
31+
2032
def test_finished_timer_ref():
2133
async def async_fn():
2234
# Making sure the event-loop won't be activated again when a finished timer gets re-refed.

0 commit comments

Comments
 (0)