[3.14] gh-139894: fix incorrect sharing of current task while forking in asyncio (GH-139897) (#139913)

* [3.14] gh-139894: fix incorrect sharing of current task while forking in `asyncio`  (GH-139897)

Fix incorrect sharing of current task with the forked child process by clearing thread state's current task and current loop in `PyOS_AfterFork_Child`.
(cherry picked from commit b881df47ff)

Co-authored-by: Kumar Aditya <kumaraditya@python.org>

* Update Lib/test/test_asyncio/test_unix_events.py
This commit is contained in:
Kumar Aditya 2025-10-10 22:36:02 +05:30 committed by GitHub
parent 60d15e1717
commit 72f25a8d9a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 49 additions and 3 deletions

View file

@ -1180,11 +1180,46 @@ async def runner():
@support.requires_fork()
class TestFork(unittest.IsolatedAsyncioTestCase):
class TestFork(unittest.TestCase):
async def test_fork_not_share_event_loop(self):
def test_fork_not_share_current_task(self):
loop = object()
task = object()
asyncio._set_running_loop(loop)
self.addCleanup(asyncio._set_running_loop, None)
asyncio.tasks._enter_task(loop, task)
self.addCleanup(asyncio.tasks._leave_task, loop, task)
self.assertIs(asyncio.current_task(), task)
r, w = os.pipe()
self.addCleanup(os.close, r)
self.addCleanup(os.close, w)
pid = os.fork()
if pid == 0:
# child
try:
asyncio._set_running_loop(loop)
current_task = asyncio.current_task()
if current_task is None:
os.write(w, b'NO TASK')
else:
os.write(w, b'TASK:' + str(id(current_task)).encode())
except BaseException as e:
os.write(w, b'ERROR:' + ascii(e).encode())
finally:
asyncio._set_running_loop(None)
os._exit(0)
else:
# parent
result = os.read(r, 100)
self.assertEqual(result, b'NO TASK')
wait_process(pid, exitcode=0)
def test_fork_not_share_event_loop(self):
# The forked process should not share the event loop with the parent
loop = asyncio.get_running_loop()
loop = object()
asyncio._set_running_loop(loop)
self.assertIs(asyncio.get_running_loop(), loop)
self.addCleanup(asyncio._set_running_loop, None)
r, w = os.pipe()
self.addCleanup(os.close, r)
self.addCleanup(os.close, w)