sim: Fix fork for multithreaded simulations

It is currently not possible to call m5.fork when the simulator is
running in with multiple parallel event queues. The POSIX standard
have very weak guarantees when forking a process with multiple
threads. In order to use fork correctly, we need to ensure that all
helper threads servicing event queues have terminated before the fork
system call is invoked.

There are two ways this could be implemented: 1) Always terminate
helper threads when taking a global simulator exit event, or 2)
terminate helper threads just before fork is called from Python.

This change implements the second strategy since the KVM-based CPUs
currently assume that TIDs don't change unless there is a fork event.

Change-Id: I22feaecd49f7f81689b43185d63a8f14428bed63
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/50408
Reviewed-by: Austin Harris <mail@austin-harris.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu>
This commit is contained in:
Andreas Sandberg
2021-09-15 13:18:21 +01:00
committed by Austin Harris
parent 17afe4e7ab
commit 8c685469f1
4 changed files with 185 additions and 73 deletions

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2012,2019 ARM Limited
# Copyright (c) 2012, 2019, 2021 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
@@ -348,6 +348,9 @@ def fork(simout="%(parent)s.f%(fork_seq)i"):
drain()
# Terminate helper threads that service parallel event queues.
_m5.event.terminateEventQueueThreads()
try:
pid = os.fork()
except OSError as e:

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017 ARM Limited
* Copyright (c) 2017, 2021 Arm Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -107,6 +107,7 @@ pybind_init_event(py::module_ &m_native)
m.def("simulate", &simulate,
py::arg("ticks") = MaxTick);
m.def("terminateEventQueueThreads", &terminateEventQueueThreads);
m.def("exitSimLoop", &exitSimLoop);
m.def("getEventQueue", []() { return curEventQueue(); },
py::return_value_policy::reference);