Gabe Black has submitted this change. ( https://gem5-review.googlesource.com/c/public/gem5/+/25144 )

Change subject: arch,cpu,dev,sim,mem: Collect System thread elements into a subclass.
......................................................................

arch,cpu,dev,sim,mem: Collect System thread elements into a subclass.

The System class has a few different arrays of values which each
correspond to a thread of execution based on their position. This
change collects them together into a single class to make managing them
easier and less error prone. It also collects methods for manipulating
those threads as an API for that class.

This class acts as a collection point for thread based state which the
System class can look into to get at all its state. It also acts as an
interface for interacting with threads for other classes. This forces
external consumers to use the API instead of accessing the individual
arrays which improves consistency.

Change-Id: Idc4575c5a0b56fe75f5c497809ad91c22bfe26cc
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/25144
Reviewed-by: Bobby R. Bruce <bbr...@ucdavis.edu>
Maintainer: Bobby R. Bruce <bbr...@ucdavis.edu>
Tested-by: kokoro <noreply+kok...@google.com>
---
M src/arch/arm/freebsd/fs_workload.cc
M src/arch/arm/fs_workload.cc
M src/arch/arm/isa.cc
M src/arch/arm/isa/insts/misc.isa
M src/arch/arm/kvm/gic.cc
M src/arch/arm/linux/fs_workload.cc
M src/arch/arm/linux/process.cc
M src/arch/arm/process.cc
M src/arch/arm/tlbi_op.hh
M src/arch/mips/process.cc
M src/arch/power/process.cc
M src/arch/riscv/bare_metal/fs_workload.cc
M src/arch/riscv/process.cc
M src/arch/sparc/fs_workload.cc
M src/arch/sparc/process.cc
M src/arch/sparc/tlb.cc
M src/arch/sparc/ua2005.cc
M src/arch/x86/fs_workload.cc
M src/arch/x86/interrupts.cc
M src/arch/x86/linux/fs_workload.cc
M src/arch/x86/process.cc
M src/cpu/base.hh
M src/cpu/intr_control.cc
M src/cpu/kvm/vm.cc
M src/cpu/o3/cpu.cc
M src/dev/arm/a9scu.cc
M src/dev/arm/fvp_base_pwr_ctrl.cc
M src/dev/arm/generic_timer.cc
M src/dev/arm/gic_v2.cc
M src/dev/arm/gic_v2.hh
M src/dev/arm/gic_v3.cc
M src/dev/arm/gic_v3_cpu_interface.cc
M src/dev/arm/gic_v3_distributor.cc
M src/dev/arm/gic_v3_redistributor.cc
M src/dev/arm/timer_cpulocal.cc
M src/dev/arm/vgic.cc
M src/dev/mips/malta_cchip.cc
M src/dev/net/dist_iface.cc
M src/dev/sparc/iob.cc
M src/dev/x86/i82094aa.cc
M src/kern/linux/linux.cc
M src/mem/abstract_mem.cc
M src/mem/cache/prefetch/queued.cc
M src/sim/mem_state.cc
M src/sim/process.cc
M src/sim/pseudo_inst.cc
M src/sim/syscall_emul.cc
M src/sim/syscall_emul.hh
M src/sim/system.cc
M src/sim/system.hh
50 files changed, 363 insertions(+), 266 deletions(-)

Approvals:
  Bobby R. Bruce: Looks good to me, approved; Looks good to me, approved
  kokoro: Regressions pass



diff --git a/src/arch/arm/freebsd/fs_workload.cc b/src/arch/arm/freebsd/fs_workload.cc
index d15e1a2..080dc35 100644
--- a/src/arch/arm/freebsd/fs_workload.cc
+++ b/src/arch/arm/freebsd/fs_workload.cc
@@ -113,7 +113,7 @@
     delete dtb_file;

     // Kernel boot requirements to set up r0, r1 and r2 in ARMv7
-    for (auto tc: system->threadContexts) {
+    for (auto *tc: system->threads) {
         tc->setIntReg(0, 0);
         tc->setIntReg(1, params()->machine_type);
         tc->setIntReg(2, params()->atags_addr + _loadAddrOffset);
diff --git a/src/arch/arm/fs_workload.cc b/src/arch/arm/fs_workload.cc
index 5bd534f..0cafb1b 100644
--- a/src/arch/arm/fs_workload.cc
+++ b/src/arch/arm/fs_workload.cc
@@ -103,7 +103,7 @@

     // FPEXC.EN = 0

-    for (auto *tc: system->threadContexts) {
+    for (auto *tc: system->threads) {
         Reset().invoke(tc);
         tc->activate();
     }
@@ -126,7 +126,7 @@
         fatal_if(!arm_sys->params()->gic_cpu_addr && is_gic_v2,
                  "gic_cpu_addr must be set with bootloader");

-        for (auto tc: arm_sys->threadContexts) {
+        for (auto *tc: arm_sys->threads) {
             if (!arm_sys->highestELIs64())
                 tc->setIntReg(3, kernelEntry);
             if (is_gic_v2)
@@ -137,7 +137,7 @@
     } else {
         // Set the initial PC to be at start of the kernel code
         if (!arm_sys->highestELIs64())
-            arm_sys->threadContexts[0]->pcState(kernelObj->entryPoint());
+            arm_sys->threads[0]->pcState(kernelObj->entryPoint());
     }
 }

diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc
index b18bbb0..b3ea91e 100644
--- a/src/arch/arm/isa.cc
+++ b/src/arch/arm/isa.cc
@@ -683,7 +683,7 @@
// mostly unimplemented, just set NumCPUs field from sim and return
             L2CTLR l2ctlr = 0;
             // b00:1CPU to b11:4CPUs
-            l2ctlr.numCPUs = tc->getSystemPtr()->numContexts() - 1;
+            l2ctlr.numCPUs = tc->getSystemPtr()->threads.size() - 1;
             return l2ctlr;
         }
       case MISCREG_DBGDIDR:
diff --git a/src/arch/arm/isa/insts/misc.isa b/src/arch/arm/isa/insts/misc.isa
index 88c473d..cd44387 100644
--- a/src/arch/arm/isa/insts/misc.isa
+++ b/src/arch/arm/isa/insts/misc.isa
@@ -780,8 +780,8 @@
     sevCode = '''
     SevMailbox = 1;
     System *sys = xc->tcBase()->getSystemPtr();
-    for (int x = 0; x < sys->numContexts(); x++) {
-        ThreadContext *oc = sys->getThreadContext(x);
+    for (int x = 0; x < sys->threads.size(); x++) {
+        ThreadContext *oc = sys->threads[x];
         if (oc == xc->tcBase())
             continue;

diff --git a/src/arch/arm/kvm/gic.cc b/src/arch/arm/kvm/gic.cc
index 14829b3..97f0fa3 100644
--- a/src/arch/arm/kvm/gic.cc
+++ b/src/arch/arm/kvm/gic.cc
@@ -302,7 +302,7 @@
MuxingKvmGic::copyBankedDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
                                   Addr daddr, size_t size)
 {
-    for (int ctx = 0; ctx < system.numContexts(); ++ctx)
+    for (int ctx = 0; ctx < system.threads.size(); ++ctx)
         for (auto a = daddr; a < daddr + size; a += 4)
             copyDistRegister(from, to, ctx, a);
 }
@@ -311,7 +311,7 @@
 MuxingKvmGic::clearBankedDistRange(BaseGicRegisters* to,
                                    Addr daddr, size_t size)
 {
-    for (int ctx = 0; ctx < system.numContexts(); ++ctx)
+    for (int ctx = 0; ctx < system.threads.size(); ++ctx)
         for (auto a = daddr; a < daddr + size; a += 4)
             to->writeDistributor(ctx, a, 0xFFFFFFFF);
 }
@@ -342,7 +342,7 @@
     // Copy CPU Interface Control Register (CTLR),
     //      Interrupt Priority Mask Register (PMR), and
     //      Binary Point Register (BPR)
-    for (int ctx = 0; ctx < system.numContexts(); ++ctx) {
+    for (int ctx = 0; ctx < system.threads.size(); ++ctx) {
         copyCpuRegister(from, to, ctx, GICC_CTLR);
         copyCpuRegister(from, to, ctx, GICC_PMR);
         copyCpuRegister(from, to, ctx, GICC_BPR);
@@ -420,7 +420,7 @@
     // have been shifted by three bits due to its having been emulated by
     // a VGIC with only 5 PMR bits in its VMCR register.  Presently the
     // Linux kernel does not repair this inaccuracy, so we correct it here.
-    for (int cpu = 0; cpu < system.numContexts(); ++cpu) {
+    for (int cpu = 0; cpu < system.threads.size(); ++cpu) {
        cpuPriority[cpu] <<= 3;
        assert((cpuPriority[cpu] & ~0xff) == 0);
     }
diff --git a/src/arch/arm/linux/fs_workload.cc b/src/arch/arm/linux/fs_workload.cc
index d45c7f0..12e3164 100644
--- a/src/arch/arm/linux/fs_workload.cc
+++ b/src/arch/arm/linux/fs_workload.cc
@@ -159,7 +159,7 @@
     }

     // Kernel boot requirements to set up r0, r1 and r2 in ARMv7
-    for (auto tc: system->threadContexts) {
+    for (auto *tc: system->threads) {
         tc->setIntReg(0, 0);
         tc->setIntReg(1, params()->machine_type);
         tc->setIntReg(2, params()->atags_addr + _loadAddrOffset);
@@ -194,7 +194,7 @@
         std::string task_filename = "tasks.txt";
         taskFile = simout.create(name() + "." + task_filename);

-        for (const auto tc : system->threadContexts) {
+        for (auto *tc: system->threads) {
             uint32_t pid = tc->getCpuPtr()->getPid();
             if (pid != BaseCPU::invldPid) {
                 mapPid(tc, pid);
@@ -265,7 +265,7 @@
 void
 FsLinux::dumpDmesg()
 {
-    Linux::dumpDmesg(system->getThreadContext(0), std::cout);
+    Linux::dumpDmesg(system->threads[0], std::cout);
 }

 /**
diff --git a/src/arch/arm/linux/process.cc b/src/arch/arm/linux/process.cc
index 4c679b3..a78c8e2 100644
--- a/src/arch/arm/linux/process.cc
+++ b/src/arch/arm/linux/process.cc
@@ -866,7 +866,7 @@
 {
     ArmProcess32::initState();
     allocateMem(commPage, PageBytes);
-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];

     uint8_t swiNeg1[] = {
         0xff, 0xff, 0xff, 0xef  // swi -1
diff --git a/src/arch/arm/process.cc b/src/arch/arm/process.cc
index 93598b0..c5ef141 100644
--- a/src/arch/arm/process.cc
+++ b/src/arch/arm/process.cc
@@ -104,8 +104,8 @@
 {
     Process::initState();
     argsInit<uint32_t>(PageBytes, INTREG_SP);
-    for (int i = 0; i < contextIds.size(); i++) {
-        ThreadContext * tc = system->getThreadContext(contextIds[i]);
+    for (auto id: contextIds) {
+        ThreadContext *tc = system->threads[id];
         CPACR cpacr = tc->readMiscReg(MISCREG_CPACR);
         // Enable the floating point coprocessors.
         cpacr.cp10 = 0x3;
@@ -123,8 +123,8 @@
 {
     Process::initState();
     argsInit<uint64_t>(PageBytes, INTREG_SP0);
-    for (int i = 0; i < contextIds.size(); i++) {
-        ThreadContext * tc = system->getThreadContext(contextIds[i]);
+    for (auto id: contextIds) {
+        ThreadContext *tc = system->threads[id];
         CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
         cpsr.mode = MODE_EL0T;
         tc->setMiscReg(MISCREG_CPSR, cpsr);
@@ -206,7 +206,7 @@

     uint32_t hwcap = 0;

-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];

     const AA64PFR0 pf_r0 = tc->readMiscReg(MISCREG_ID_AA64PFR0_EL1);

@@ -441,7 +441,7 @@

     initVirtMem->writeBlob(argc_base, &guestArgc, intSize);

-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];
     //Set the stack pointer register
     tc->setIntReg(spIndex, memState->getStackMin());
     //A pointer to a function to run when the program exits. We'll set this
diff --git a/src/arch/arm/tlbi_op.hh b/src/arch/arm/tlbi_op.hh
index 03a0a3e..8706d3d 100644
--- a/src/arch/arm/tlbi_op.hh
+++ b/src/arch/arm/tlbi_op.hh
@@ -68,11 +68,8 @@
     void
     broadcast(ThreadContext *tc)
     {
-        System *sys = tc->getSystemPtr();
-        for (int x = 0; x < sys->numContexts(); x++) {
-            ThreadContext *oc = sys->getThreadContext(x);
+        for (auto *oc: tc->getSystemPtr()->threads)
             (*this)(oc);
-        }
     }

   protected:
diff --git a/src/arch/mips/process.cc b/src/arch/mips/process.cc
index f6587ab..cdda2b2 100644
--- a/src/arch/mips/process.cc
+++ b/src/arch/mips/process.cc
@@ -193,7 +193,7 @@
     initVirtMem->write(auxv_array_end, zero);
     auxv_array_end += sizeof(zero);

-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];

     tc->setIntReg(FirstArgumentReg, argc);
     tc->setIntReg(FirstArgumentReg + 1, argv_array_base);
diff --git a/src/arch/power/process.cc b/src/arch/power/process.cc
index 01a2c9f..767c3eb 100644
--- a/src/arch/power/process.cc
+++ b/src/arch/power/process.cc
@@ -267,7 +267,7 @@

     initVirtMem->writeBlob(argc_base, &guestArgc, intSize);

-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];

     //Set the stack pointer register
     tc->setIntReg(StackPointerReg, stack_min);
diff --git a/src/arch/riscv/bare_metal/fs_workload.cc b/src/arch/riscv/bare_metal/fs_workload.cc
index 6a0c86c..9c90c68 100644
--- a/src/arch/riscv/bare_metal/fs_workload.cc
+++ b/src/arch/riscv/bare_metal/fs_workload.cc
@@ -54,7 +54,7 @@
 {
     RiscvISA::FsWorkload::initState();

-    for (auto *tc: system->threadContexts) {
+    for (auto *tc: system->threads) {
         RiscvISA::Reset().invoke(tc);
         tc->activate();
     }
@@ -62,7 +62,7 @@
     warn_if(!bootloader->buildImage().write(system->physProxy),
             "Could not load sections to memory.");

-    for (auto *tc: system->threadContexts) {
+    for (auto *tc: system->threads) {
         RiscvISA::Reset().invoke(tc);
         tc->activate();
     }
diff --git a/src/arch/riscv/process.cc b/src/arch/riscv/process.cc
index 9c05400..a17b515 100644
--- a/src/arch/riscv/process.cc
+++ b/src/arch/riscv/process.cc
@@ -99,7 +99,7 @@

     argsInit<uint64_t>(PageBytes);
     for (ContextID ctx: contextIds)
- system->getThreadContext(ctx)->setMiscRegNoEffect(MISCREG_PRV, PRV_U);
+        system->threads[ctx]->setMiscRegNoEffect(MISCREG_PRV, PRV_U);
 }

 void
@@ -109,10 +109,11 @@

     argsInit<uint32_t>(PageBytes);
     for (ContextID ctx: contextIds) {
- system->getThreadContext(ctx)->setMiscRegNoEffect(MISCREG_PRV, PRV_U);
-        PCState pc = system->getThreadContext(ctx)->pcState();
+        auto *tc = system->threads[ctx];
+        tc->setMiscRegNoEffect(MISCREG_PRV, PRV_U);
+        PCState pc = tc->pcState();
         pc.rv32(true);
-        system->getThreadContext(ctx)->pcState(pc);
+        tc->pcState(pc);
     }
 }

@@ -239,7 +240,7 @@
         pushOntoStack(aux.val);
     }

-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];
     tc->setIntReg(StackPointerReg, memState->getStackMin());
     tc->pcState(getStartPC());

diff --git a/src/arch/sparc/fs_workload.cc b/src/arch/sparc/fs_workload.cc
index 71c3b45..b812f59 100644
--- a/src/arch/sparc/fs_workload.cc
+++ b/src/arch/sparc/fs_workload.cc
@@ -40,11 +40,11 @@
 {
     Workload::initState();

-    if (system->threadContexts.empty())
+    if (system->threads.empty())
         return;

     // Other CPUs will get activated by IPIs.
-    auto *tc = system->threadContexts[0];
+    auto *tc = system->threads[0];
     SparcISA::PowerOnReset().invoke(tc);
     tc->activate();
 }
diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc
index 3edbdf5..ca0df08 100644
--- a/src/arch/sparc/process.cc
+++ b/src/arch/sparc/process.cc
@@ -111,7 +111,7 @@
 {
     Process::initState();

-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];
     // From the SPARC ABI

     // Setup default FP state
@@ -155,7 +155,7 @@
 {
     SparcProcess::initState();

-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];
     // The process runs in user mode with 32 bit addresses
     PSTATE pstate = 0;
     pstate.ie = 1;
@@ -170,7 +170,7 @@
 {
     SparcProcess::initState();

-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];
     // The process runs in user mode
     PSTATE pstate = 0;
     pstate.ie = 1;
@@ -393,7 +393,7 @@
     fillStart = memState->getStackBase();
     spillStart = fillStart + sizeof(MachInst) * numFillInsts;

-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];
     // Set up the thread context to start running the process
     // assert(NumArgumentRegs >= 2);
     // tc->setIntReg(ArgumentReg[0], argc);
diff --git a/src/arch/sparc/tlb.cc b/src/arch/sparc/tlb.cc
index e67ae9a..fcb0973 100644
--- a/src/arch/sparc/tlb.cc
+++ b/src/arch/sparc/tlb.cc
@@ -1372,8 +1372,8 @@
         }
         break;
       case ASI_SWVR_UDB_INTR_W:
- tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
-            postInterrupt(0, bits(data, 5, 0), 0);
+            tc->getSystemPtr()->threads[bits(data,12,8)]->
+                getCpuPtr()->postInterrupt(0, bits(data, 5, 0), 0);
         break;
       default:
 doMmuWriteError:
diff --git a/src/arch/sparc/ua2005.cc b/src/arch/sparc/ua2005.cc
index 389549b..3403451 100644
--- a/src/arch/sparc/ua2005.cc
+++ b/src/arch/sparc/ua2005.cc
@@ -287,12 +287,12 @@
temp = readMiscRegNoEffect(miscReg) & (STS::active | STS::speculative);
         // Check that the CPU array is fully populated
         // (by calling getNumCPus())
-        assert(sys->numContexts() > tc->contextId());
+        assert(sys->threads.size() > tc->contextId());

         temp |= tc->contextId()  << STS::shft_id;

- for (x = tc->contextId() & ~3; x < sys->threadContexts.size(); x++) {
-            switch (sys->threadContexts[x]->status()) {
+        for (x = tc->contextId() & ~3; x < sys->threads.size(); x++) {
+            switch (sys->threads[x]->status()) {
               case ThreadContext::Active:
                 temp |= STS::st_run << (STS::shft_fsm0 -
                         ((x & 0x3) * (STS::shft_fsm0-STS::shft_fsm1)));
diff --git a/src/arch/x86/fs_workload.cc b/src/arch/x86/fs_workload.cc
index 3f46eba..44c01d7 100644
--- a/src/arch/x86/fs_workload.cc
+++ b/src/arch/x86/fs_workload.cc
@@ -106,7 +106,7 @@
 {
     KernelWorkload::initState();

-    for (auto *tc: system->threadContexts) {
+    for (auto *tc: system->threads) {
         X86ISA::InitInterrupt(0).invoke(tc);

         if (tc->contextId() == 0) {
@@ -124,7 +124,7 @@
     fatal_if(kernelObj->getArch() == Loader::I386,
              "Loading a 32 bit x86 kernel is not supported.");

-    ThreadContext *tc = system->threadContexts[0];
+    ThreadContext *tc = system->threads[0];
     auto phys_proxy = system->physProxy;

     // This is the boot strap processor (BSP). Initialize it to look like
diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc
index c2dcb32..c81cf62 100644
--- a/src/arch/x86/interrupts.cc
+++ b/src/arch/x86/interrupts.cc
@@ -479,7 +479,7 @@
             message.level = low.level;
             message.trigger = low.trigger;
             std::list<int> apics;
-            int numContexts = sys->numContexts();
+            int numContexts = sys->threads.size();
             switch (low.destShorthand) {
               case 0:
                 if (message.deliveryMode == DeliveryMode::LowestPriority) {
diff --git a/src/arch/x86/linux/fs_workload.cc b/src/arch/x86/linux/fs_workload.cc
index 4f83884..0303cc8 100644
--- a/src/arch/x86/linux/fs_workload.cc
+++ b/src/arch/x86/linux/fs_workload.cc
@@ -123,7 +123,7 @@
      * Pass the location of the real mode data structure to the kernel
      * using register %esi. We'll use %rsi which should be equivalent.
      */
-    system->threadContexts[0]->setIntReg(INTREG_RSI, realModeData);
+    system->threads[0]->setIntReg(INTREG_RSI, realModeData);
 }

 } // namespace X86ISA
diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc
index 1b7fd3e..0324e94 100644
--- a/src/arch/x86/process.cc
+++ b/src/arch/x86/process.cc
@@ -303,7 +303,7 @@
         tss_attr.unusable = 0;

         for (int i = 0; i < contextIds.size(); i++) {
-            ThreadContext * tc = system->getThreadContext(contextIds[i]);
+            ThreadContext *tc = system->threads[contextIds[i]];

             tc->setMiscReg(MISCREG_CS, cs);
             tc->setMiscReg(MISCREG_DS, ds);
@@ -514,7 +514,7 @@
                     16 * PageBytes, false);
     } else {
         for (int i = 0; i < contextIds.size(); i++) {
-            ThreadContext * tc = system->getThreadContext(contextIds[i]);
+            ThreadContext * tc = system->threads[contextIds[i]];

             SegAttr dataAttr = 0;
             dataAttr.dpl = 3;
@@ -625,7 +625,7 @@
             vsysexitBlob, sizeof(vsysexitBlob));

     for (int i = 0; i < contextIds.size(); i++) {
-        ThreadContext * tc = system->getThreadContext(contextIds[i]);
+        ThreadContext * tc = system->threads[contextIds[i]];

         SegAttr dataAttr = 0;
         dataAttr.dpl = 3;
@@ -975,7 +975,7 @@

     initVirtMem->writeBlob(argc_base, &guestArgc, intSize);

-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];
     // Set the stack pointer register
     tc->setIntReg(StackPointerReg, stack_min);

diff --git a/src/cpu/base.hh b/src/cpu/base.hh
index a33d1bd..810f267 100644
--- a/src/cpu/base.hh
+++ b/src/cpu/base.hh
@@ -54,6 +54,7 @@
 #include "arch/isa_traits.hh"
 #include "arch/microcode_rom.hh"
 #include "base/statistics.hh"
+#include "mem/port_proxy.hh"
 #include "sim/clocked_object.hh"
 #include "sim/eventq.hh"
 #include "sim/full_system.hh"
diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc
index 9274b37..9b4a352 100644
--- a/src/cpu/intr_control.cc
+++ b/src/cpu/intr_control.cc
@@ -47,7 +47,7 @@
 IntrControl::post(int cpu_id, int int_num, int index)
 {
     DPRINTF(IntrControl, "post  %d:%d (cpu %d)\n", int_num, index, cpu_id);
-    ThreadContext *tc = sys->getThreadContext(cpu_id);
+    auto *tc = sys->threads[cpu_id];
     tc->getCpuPtr()->postInterrupt(tc->threadId(), int_num, index);
 }

@@ -55,7 +55,7 @@
 IntrControl::clear(int cpu_id, int int_num, int index)
 {
     DPRINTF(IntrControl, "clear %d:%d (cpu %d)\n", int_num, index, cpu_id);
-    ThreadContext *tc = sys->getThreadContext(cpu_id);
+    auto *tc = sys->threads[cpu_id];
     tc->getCpuPtr()->clearInterrupt(tc->threadId(), int_num, index);
 }

@@ -63,7 +63,7 @@
 IntrControl::clearAll(int cpu_id)
 {
DPRINTF(IntrControl, "Clear all pending interrupts for CPU %d\n", cpu_id);
-    ThreadContext *tc = sys->getThreadContext(cpu_id);
+    auto *tc = sys->threads[cpu_id];
     tc->getCpuPtr()->clearInterrupts(tc->threadId());
 }

@@ -71,7 +71,7 @@
 IntrControl::havePosted(int cpu_id) const
 {
     DPRINTF(IntrControl, "Check pending interrupts for CPU %d\n", cpu_id);
-    ThreadContext *tc = sys->getThreadContext(cpu_id);
+    auto *tc = sys->threads[cpu_id];
     return tc->getCpuPtr()->checkInterrupts(tc);
 }

diff --git a/src/cpu/kvm/vm.cc b/src/cpu/kvm/vm.cc
index 9808d61..720548c 100644
--- a/src/cpu/kvm/vm.cc
+++ b/src/cpu/kvm/vm.cc
@@ -539,7 +539,7 @@
 {
     assert(system != nullptr);
     return dynamic_cast<BaseKvmCPU*>
-        (system->getThreadContext(ctx)->getCpuPtr())->getVCpuID();
+        (system->threads[ctx]->getCpuPtr())->getVCpuID();
 }

 int
diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc
index 5f0a98b..5230ee9 100644
--- a/src/cpu/o3/cpu.cc
+++ b/src/cpu/o3/cpu.cc
@@ -757,7 +757,7 @@
     // and not in the ThreadContext.
     ThreadContext *src_tc;
     if (FullSystem)
-        src_tc = system->threadContexts[tid];
+        src_tc = system->threads[tid];
     else
         src_tc = tcBase(tid);

diff --git a/src/dev/arm/a9scu.cc b/src/dev/arm/a9scu.cc
index 629fdd9..5101682 100644
--- a/src/dev/arm/a9scu.cc
+++ b/src/dev/arm/a9scu.cc
@@ -60,20 +60,23 @@
         pkt->setLE(1); // SCU already enabled
         break;
       case Config:
- /* Without making a completely new SCU, we can use the core count field
-         * as 4 bits and inform the OS of up to 16 CPUs.  Although the core
- * count is technically bits [1:0] only, bits [3:2] are SBZ for future
-         * expansion like this.
-         */
-        if (sys->numContexts() > 4) {
-            warn_once("A9SCU with >4 CPUs is unsupported\n");
-            if (sys->numContexts() > 15)
- fatal("Too many CPUs (%d) for A9SCU!\n", sys->numContexts());
+        {
+ /* Without making a completely new SCU, we can use the core count + * field as 4 bits and inform the OS of up to 16 CPUs. Although + * the core count is technically bits [1:0] only, bits [3:2] are
+             * SBZ for future expansion like this.
+             */
+            int threads = sys->threads.size();
+            if (threads > 4) {
+                warn_once("A9SCU with >4 CPUs is unsupported");
+                fatal_if(threads > 15,
+                        "Too many CPUs (%d) for A9SCU!", threads);
+            }
+            int smp_bits, core_cnt;
+            smp_bits = (1 << threads) - 1;
+            core_cnt = threads - 1;
+            pkt->setLE(smp_bits << 4 | core_cnt);
         }
-        int smp_bits, core_cnt;
-        smp_bits = (1 << sys->numContexts()) - 1;
-        core_cnt = sys->numContexts() - 1;
-        pkt->setLE(smp_bits << 4 | core_cnt);
         break;
       default:
         // Only configuration register is implemented
diff --git a/src/dev/arm/fvp_base_pwr_ctrl.cc b/src/dev/arm/fvp_base_pwr_ctrl.cc
index 5113c92..7ab4e40 100644
--- a/src/dev/arm/fvp_base_pwr_ctrl.cc
+++ b/src/dev/arm/fvp_base_pwr_ctrl.cc
@@ -61,8 +61,8 @@
 FVPBasePwrCtrl::init()
 {
     // All cores are ON by default (PwrStatus.{l0,l1} = 0b1)
-    corePwrStatus.resize(sys->numContexts(), 0x60000000);
-    for (const auto &tc : sys->threadContexts)
+    corePwrStatus.resize(sys->threads.size(), 0x60000000);
+    for (const auto &tc : sys->threads)
         poweredCoresPerCluster[tc->socketId()] += 1;
     BasicPioDevice::init();
 }
@@ -200,7 +200,7 @@
             regs.pcoffr = ~0;
         } else if (pwrs->l0) {
             // Power off all cores in the cluster
-            for (const auto &tco : sys->threadContexts) {
+            for (const auto &tco : sys->threads) {
                 if (tc->socketId() == tco->socketId()) {
                     PwrStatus *npwrs = getCorePwrStatus(tco);
                     // Set pending cluster power off
@@ -257,7 +257,7 @@
 ThreadContext *
 FVPBasePwrCtrl::getThreadContextByMPID(uint32_t mpid) const
 {
-    for (auto &tc : sys->threadContexts) {
+    for (auto &tc : sys->threads) {
         if (mpid == ArmISA::getAffinity(&system, tc))
             return tc;
     }
@@ -274,7 +274,7 @@
     // Clear pending power-offs to the core
     pwrs->pp = 0;
     // Clear pending power-offs to the core's cluster
-    for (const auto &tco : sys->threadContexts) {
+    for (const auto &tco : sys->threads) {
         if (tc->socketId() == tco->socketId()) {
             PwrStatus *npwrs = getCorePwrStatus(tco);
             npwrs->pc = 0;
diff --git a/src/dev/arm/generic_timer.cc b/src/dev/arm/generic_timer.cc
index 51a52c7..4f92dac 100644
--- a/src/dev/arm/generic_timer.cc
+++ b/src/dev/arm/generic_timer.cc
@@ -440,7 +440,7 @@
     timers.resize(cpus);
     for (unsigned i = old_cpu_count; i < cpus; ++i) {

-        ThreadContext *tc = system.getThreadContext(i);
+        ThreadContext *tc = system.threads[i];

         timers[i].reset(
             new CoreTimers(*this, system, i,
@@ -481,7 +481,7 @@
 GenericTimer::setMiscReg(int reg, unsigned cpu, RegVal val)
 {
     CoreTimers &core(getTimers(cpu));
-    ThreadContext *tc = system.getThreadContext(cpu);
+    ThreadContext *tc = system.threads[cpu];

     switch (reg) {
       case MISCREG_CNTFRQ:
@@ -695,7 +695,7 @@
     ArmInterruptPin *_irqVirt, ArmInterruptPin *_irqHyp)
       : parent(_parent),
         cntfrq(parent.params()->cntfrq),
-        threadContext(system.getThreadContext(cpu)),
+        threadContext(system.threads[cpu]),
         irqPhysS(_irqPhysS),
         irqPhysNS(_irqPhysNS),
         irqVirt(_irqVirt),
diff --git a/src/dev/arm/gic_v2.cc b/src/dev/arm/gic_v2.cc
index c4834ec..4ef1517 100644
--- a/src/dev/arm/gic_v2.cc
+++ b/src/dev/arm/gic_v2.cc
@@ -263,7 +263,7 @@
         /* The 0x100 is a made-up flag to show that gem5 extensions
          * are available,
          * write 0x200 to this register to enable it.  */
-        return (((sys->numRunningContexts() - 1) << 5) |
+        return (((sys->threads.numRunning() - 1) << 5) |
                 (itLines/INT_BITS_MAX -1) |
                 (haveGem5Extensions ? 0x100 : 0x0));
       case GICD_PIDR0:
@@ -291,10 +291,9 @@

     assert(pkt->req->hasContextId());
     const ContextID ctx = pkt->req->contextId();
-    assert(ctx < sys->numRunningContexts());
+    assert(ctx < sys->threads.numRunning());

-    DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr,
-            ctx);
+ DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr, ctx);

     pkt->setLE<uint32_t>(readCpu(ctx, daddr));

@@ -326,7 +325,7 @@
                     panic_if(!cpuSgiPending[active_int],
"Interrupt %d active but no CPU generated it?\n",
                             active_int);
-                    for (int x = 0; x < sys->numRunningContexts(); x++) {
+                    for (int x = 0; x < sys->threads.numRunning(); x++) {
                         // See which CPU generated the interrupt
                         uint8_t cpugen =
bits(cpuSgiPending[active_int], 7 + 8 * x, 8 * x);
@@ -660,7 +659,7 @@
           } break;
           case 1: {
              // interrupt all
-             for (int i = 0; i < sys->numContexts(); i++) {
+             for (int i = 0; i < sys->threads.size(); i++) {
                  DPRINTF(IPI, "Processing CPU %d\n", i);
                  if (!cpuEnabled(i))
                      continue;
@@ -686,7 +685,7 @@
             // interrupt all
             uint8_t cpu_list;
             cpu_list = 0;
-            for (int x = 0; x < sys->numContexts(); x++)
+            for (int x = 0; x < sys->threads.size(); x++)
                 cpu_list |= cpuEnabled(x) ? 1 << x : 0;
             swi.cpu_list = cpu_list;
             break;
@@ -699,7 +698,7 @@

         DPRINTF(IPI, "Generating softIRQ from CPU %d for %#x\n", ctx,
                 swi.cpu_list);
-        for (int i = 0; i < sys->numContexts(); i++) {
+        for (int i = 0; i < sys->threads.size(); i++) {
             DPRINTF(IPI, "Processing CPU %d\n", i);
             if (!cpuEnabled(i))
                 continue;
@@ -715,8 +714,7 @@
 uint64_t
 GicV2::genSwiMask(int cpu)
 {
-    if (cpu > sys->numContexts())
-        panic("Invalid CPU ID\n");
+    panic_if(cpu > sys->threads.size(), "Invalid CPU ID.");
     return ULL(0x0101010101010101) << cpu;
 }

@@ -734,7 +732,7 @@
 void
 GicV2::updateIntState(int hint)
 {
-    for (int cpu = 0; cpu < sys->numContexts(); cpu++) {
+    for (int cpu = 0; cpu < sys->threads.size(); cpu++) {
         if (!cpuEnabled(cpu))
             continue;

@@ -773,7 +771,7 @@
             }
         }

-        bool mp_sys = sys->numRunningContexts() > 1;
+        bool mp_sys = sys->threads.numRunning() > 1;
         // Check other ints
         for (int x = 0; x < (itLines/INT_BITS_MAX); x++) {
             if (getIntEnabled(cpu, x) & getPendingInt(cpu, x)) {
@@ -832,7 +830,7 @@
 void
 GicV2::updateRunPri()
 {
-    for (int cpu = 0; cpu < sys->numContexts(); cpu++) {
+    for (int cpu = 0; cpu < sys->threads.size(); cpu++) {
         if (!cpuEnabled(cpu))
             continue;
         uint8_t maxPriority = 0xff;
diff --git a/src/dev/arm/gic_v2.hh b/src/dev/arm/gic_v2.hh
index 5bc74b2..600f9af 100644
--- a/src/dev/arm/gic_v2.hh
+++ b/src/dev/arm/gic_v2.hh
@@ -297,7 +297,7 @@
     uint8_t cpuTarget[GLOBAL_INT_LINES];

     uint8_t getCpuTarget(ContextID ctx, uint32_t ix) {
-        assert(ctx < sys->numRunningContexts());
+        assert(ctx < sys->threads.numRunning());
         assert(ix < INT_LINES_MAX);
         if (ix < SGI_MAX + PPI_MAX) {
             // "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each
diff --git a/src/dev/arm/gic_v3.cc b/src/dev/arm/gic_v3.cc
index 2103c0e..b404601 100644
--- a/src/dev/arm/gic_v3.cc
+++ b/src/dev/arm/gic_v3.cc
@@ -60,15 +60,15 @@
 Gicv3::init()
 {
     distributor = new Gicv3Distributor(this, params()->it_lines);
-    redistributors.resize(sys->numContexts(), nullptr);
-    cpuInterfaces.resize(sys->numContexts(), nullptr);
+    int threads = sys->threads.size();
+    redistributors.resize(threads, nullptr);
+    cpuInterfaces.resize(threads, nullptr);

-    panic_if(sys->numContexts() > params()->cpu_max,
+    panic_if(threads > params()->cpu_max,
         "Exceeding maximum number of PEs supported by GICv3: "
-        "using %u while maximum is %u\n", sys->numContexts(),
-        params()->cpu_max);
+        "using %u while maximum is %u.", threads, params()->cpu_max);

-    for (int i = 0; i < sys->numContexts(); i++) {
+    for (int i = 0; i < threads; i++) {
         redistributors[i] = new Gicv3Redistributor(this, i);
         cpuInterfaces[i] = new Gicv3CPUInterface(this, i);
     }
@@ -77,14 +77,13 @@
         Gicv3Distributor::ADDR_RANGE_SIZE - 1);

     redistSize = redistributors[0]->addrRangeSize;
-    redistRange = RangeSize(params()->redist_addr,
-         redistSize * sys->numContexts() - 1);
+ redistRange = RangeSize(params()->redist_addr, redistSize * threads - 1);

     addrRanges = {distRange, redistRange};

     distributor->init();

-    for (int i = 0; i < sys->numContexts(); i++) {
+    for (int i = 0; i < threads; i++) {
         redistributors[i]->init();
         cpuInterfaces[i]->init();
     }
@@ -205,7 +204,7 @@
 Gicv3::postInt(uint32_t cpu, ArmISA::InterruptTypes int_type)
 {
     platform->intrctrl->post(cpu, int_type, 0);
-    ArmSystem::callClearStandByWfi(sys->getThreadContext(cpu));
+    ArmSystem::callClearStandByWfi(sys->threads[cpu]);
 }

 bool
diff --git a/src/dev/arm/gic_v3_cpu_interface.cc b/src/dev/arm/gic_v3_cpu_interface.cc
index 73bd3bc..5e1f871 100644
--- a/src/dev/arm/gic_v3_cpu_interface.cc
+++ b/src/dev/arm/gic_v3_cpu_interface.cc
@@ -1776,7 +1776,7 @@

     bool ns = !inSecureState();

-    for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
+    for (int i = 0; i < gic->getSystem()->threads.size(); i++) {
         Gicv3Redistributor * redistributor_i =
             gic->getRedistributor(i);
         uint32_t affinity_i = redistributor_i->getAffinity();
@@ -2587,7 +2587,7 @@
 void
 Gicv3CPUInterface::assertWakeRequest()
 {
-    ThreadContext *tc = gic->getSystem()->getThreadContext(cpuId);
+    auto *tc = gic->getSystem()->threads[cpuId];
     if (ArmSystem::callSetWakeRequest(tc)) {
         Reset().invoke(tc);
         tc->activate();
@@ -2597,7 +2597,7 @@
 void
 Gicv3CPUInterface::deassertWakeRequest()
 {
-    ThreadContext *tc = gic->getSystem()->getThreadContext(cpuId);
+    auto *tc = gic->getSystem()->threads[cpuId];
     ArmSystem::callClearWakeRequest(tc);
 }

diff --git a/src/dev/arm/gic_v3_distributor.cc b/src/dev/arm/gic_v3_distributor.cc
index 4ce9782..485ba72 100644
--- a/src/dev/arm/gic_v3_distributor.cc
+++ b/src/dev/arm/gic_v3_distributor.cc
@@ -1021,7 +1021,7 @@

     if (affinity_routing.IRM) {
         // Interrupts routed to any PE defined as a participating node
-        for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
+        for (int i = 0; i < gic->getSystem()->threads.size(); i++) {
             Gicv3Redistributor * redistributor_i =
                 gic->getRedistributor(i);

@@ -1086,7 +1086,7 @@
     }

     // Update all redistributors
-    for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
+    for (int i = 0; i < gic->getSystem()->threads.size(); i++) {
         gic->getRedistributor(i)->update();
     }
 }
diff --git a/src/dev/arm/gic_v3_redistributor.cc b/src/dev/arm/gic_v3_redistributor.cc
index 7408949..5fceed5 100644
--- a/src/dev/arm/gic_v3_redistributor.cc
+++ b/src/dev/arm/gic_v3_redistributor.cc
@@ -158,7 +158,7 @@
            * (physical LPIs supported)
            */
           uint64_t affinity = getAffinity();
-          int last = cpuId == (gic->getSystem()->numContexts() - 1);
+          int last = cpuId == (gic->getSystem()->threads.size() - 1);
           return (affinity << 32) | (1 << 24) | (cpuId << 8) |
               (1 << 5) | (last << 4) | (1 << 3) | (1 << 0);
       }
@@ -990,7 +990,7 @@
 uint32_t
 Gicv3Redistributor::getAffinity() const
 {
-    ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId);
+    ThreadContext *tc = gic->getSystem()->threads[cpuId];
     uint64_t mpidr = getMPIDR(gic->getSystem(), tc);
     /*
      * Aff3 = MPIDR[39:32]
diff --git a/src/dev/arm/timer_cpulocal.cc b/src/dev/arm/timer_cpulocal.cc
index 41cdbc3..5ba0b16 100644
--- a/src/dev/arm/timer_cpulocal.cc
+++ b/src/dev/arm/timer_cpulocal.cc
@@ -56,8 +56,8 @@
 {
    auto p = params();
    // Initialize the timer registers for each per cpu timer
-   for (int i = 0; i < sys->numContexts(); i++) {
-        ThreadContext* tc = sys->getThreadContext(i);
+   for (int i = 0; i < sys->threads.size(); i++) {
+        ThreadContext* tc = sys->threads[i];
         std::stringstream oss;
         oss << name() << ".timer" << i;

@@ -429,14 +429,14 @@
 void
 CpuLocalTimer::serialize(CheckpointOut &cp) const
 {
-    for (int i = 0; i < sys->numContexts(); i++)
+    for (int i = 0; i < sys->threads.size(); i++)
         localTimer[i]->serializeSection(cp, csprintf("timer%d", i));
 }

 void
 CpuLocalTimer::unserialize(CheckpointIn &cp)
 {
-    for (int i = 0; i < sys->numContexts(); i++)
+    for (int i = 0; i < sys->threads.size(); i++)
         localTimer[i]->unserializeSection(cp, csprintf("timer%d", i));
 }

diff --git a/src/dev/arm/vgic.cc b/src/dev/arm/vgic.cc
index 0bb1fef..5ac597b 100644
--- a/src/dev/arm/vgic.cc
+++ b/src/dev/arm/vgic.cc
@@ -56,7 +56,7 @@
         maintIntPosted[x] = false;
         vIntPosted[x] = false;
     }
-    assert(sys->numRunningContexts() <= VGIC_CPU_MAX);
+    assert(sys->threads.numRunning() <= VGIC_CPU_MAX);
 }

 VGic::~VGic()
@@ -414,8 +414,8 @@
         }
     }

-    assert(sys->numRunningContexts() <= VGIC_CPU_MAX);
-    for (int i = 0; i < sys->numRunningContexts(); i++) {
+    assert(sys->threads.numRunning() <= VGIC_CPU_MAX);
+    for (int i = 0; i < sys->threads.numRunning(); i++) {
         struct vcpuIntData *vid = &vcpuData[i];
         // Are any LRs active that weren't before?
         if (!vIntPosted[i]) {
diff --git a/src/dev/mips/malta_cchip.cc b/src/dev/mips/malta_cchip.cc
index 001202e..c8fe7a8 100644
--- a/src/dev/mips/malta_cchip.cc
+++ b/src/dev/mips/malta_cchip.cc
@@ -102,7 +102,7 @@
 void
 MaltaCChip::postIntr(uint32_t interrupt)
 {
-    uint64_t size = sys->threadContexts.size();
+    uint64_t size = sys->threads.size();
     assert(size <= Malta::Max_CPUs);

     for (int i=0; i < size; i++) {
@@ -117,7 +117,7 @@
 void
 MaltaCChip::clearIntr(uint32_t interrupt)
 {
-    uint64_t size = sys->threadContexts.size();
+    uint64_t size = sys->threads.size();
     assert(size <= Malta::Max_CPUs);

     for (int i=0; i < size; i++) {
diff --git a/src/dev/net/dist_iface.cc b/src/dev/net/dist_iface.cc
index 4693350..cc408e0 100644
--- a/src/dev/net/dist_iface.cc
+++ b/src/dev/net/dist_iface.cc
@@ -410,9 +410,7 @@
             start();
         } else {
             // Wake up thread contexts on non-switch nodes.
- for (int i = 0; i < DistIface::master->sys->numContexts(); i++) {
-                ThreadContext *tc =
-                    DistIface::master->sys->getThreadContext(i);
+            for (auto *tc: master->sys->threads) {
                 if (tc->status() == ThreadContext::Suspended)
                     tc->activate();
                 else
@@ -868,8 +866,7 @@
         // Dist-gem5 will reactivate all thread contexts when everyone has
         // reached the sync stop point.
 #if THE_ISA != NULL_ISA
-        for (int i = 0; i < master->sys->numContexts(); i++) {
-            ThreadContext *tc = master->sys->getThreadContext(i);
+        for (auto *tc: master->sys->threads) {
             if (tc->status() == ThreadContext::Active)
                 tc->quiesce();
         }
@@ -883,8 +880,7 @@
         // activation here, since we know exactly when the next sync will
         // occur.
 #if THE_ISA != NULL_ISA
-        for (int i = 0; i < master->sys->numContexts(); i++) {
-            ThreadContext *tc = master->sys->getThreadContext(i);
+        for (auto *tc: master->sys->threads) {
             if (tc->status() == ThreadContext::Active)
                 tc->quiesceTick(master->syncEvent->when() + 1);
         }
diff --git a/src/dev/sparc/iob.cc b/src/dev/sparc/iob.cc
index 347872e..44e7dc8 100644
--- a/src/dev/sparc/iob.cc
+++ b/src/dev/sparc/iob.cc
@@ -58,7 +58,7 @@
     iobManSize = ULL(0x0100000000);
     iobJBusAddr = ULL(0x9F00000000);
     iobJBusSize = ULL(0x0100000000);
-    assert (params()->system->threadContexts.size() <= MaxNiagaraProcs);
+    assert(params()->system->threads.size() <= MaxNiagaraProcs);

     pioDelay = p->pio_latency;

@@ -276,7 +276,7 @@
 Iob::generateIpi(Type type, int cpu_id, int vector)
 {
SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
-    if (cpu_id >= sys->numContexts())
+    if (cpu_id >= sys->threads.size())
         return;

     switch (type) {
@@ -289,16 +289,16 @@
         warn("Sending reset to CPU: %d\n", cpu_id);
         if (vector != por->trapType())
             panic("Don't know how to set non-POR reset to cpu\n");
-        por->invoke(sys->threadContexts[cpu_id]);
-        sys->threadContexts[cpu_id]->activate();
+        por->invoke(sys->threads[cpu_id]);
+        sys->threads[cpu_id]->activate();
         break;
case 2: // idle -- this means stop executing and don't wake on interrupts
         DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id);
-        sys->threadContexts[cpu_id]->halt();
+        sys->threads[cpu_id]->halt();
         break;
       case 3: // resume
DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id);
-        sys->threadContexts[cpu_id]->activate();
+        sys->threads[cpu_id]->activate();
         break;
       default:
         panic("Invalid type to generate ipi\n");
diff --git a/src/dev/x86/i82094aa.cc b/src/dev/x86/i82094aa.cc
index cc51d5c..8d91cc6 100644
--- a/src/dev/x86/i82094aa.cc
+++ b/src/dev/x86/i82094aa.cc
@@ -198,7 +198,7 @@
         message.level = entry.polarity;
         message.trigger = entry.trigger;
         std::list<int> apics;
-        int numContexts = sys->numContexts();
+        int numContexts = sys->threads.size();
         if (message.destMode == 0) {
             if (message.deliveryMode == DeliveryMode::LowestPriority) {
                 panic("Lowest priority delivery mode from the "
@@ -214,7 +214,7 @@
             }
         } else {
             for (int i = 0; i < numContexts; i++) {
-                BaseInterrupts *base_int = sys->getThreadContext(i)->
+                BaseInterrupts *base_int = sys->threads[i]->
                     getCpuPtr()->getInterruptController(0);
                 auto *localApic = dynamic_cast<Interrupts *>(base_int);
                 if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) &
diff --git a/src/kern/linux/linux.cc b/src/kern/linux/linux.cc
index ae1d47c..c27d053 100644
--- a/src/kern/linux/linux.cc
+++ b/src/kern/linux/linux.cc
@@ -110,8 +110,7 @@
 std::string
 Linux::cpuOnline(Process *process, ThreadContext *tc)
 {
-    return csprintf("0-%d\n",
-                    tc->getSystemPtr()->numContexts() - 1);
+    return csprintf("0-%d\n", tc->getSystemPtr()->threads.size() - 1);
 }

 std::string
diff --git a/src/mem/abstract_mem.cc b/src/mem/abstract_mem.cc
index 70d4626..2f72ebe 100644
--- a/src/mem/abstract_mem.cc
+++ b/src/mem/abstract_mem.cc
@@ -328,7 +328,7 @@
                                            req->contextId() :
                                            InvalidContextID;
                 if (owner_cid != requester_cid) {
- ThreadContext* ctx = system()->getThreadContext(owner_cid);
+                    ThreadContext* ctx = system()->threads[owner_cid];
                     TheISA::globalClearExclusive(ctx);
                 }
                 i = lockedAddrList.erase(i);
diff --git a/src/mem/cache/prefetch/queued.cc b/src/mem/cache/prefetch/queued.cc
index e6d2b7c..c2ae090 100644
--- a/src/mem/cache/prefetch/queued.cc
+++ b/src/mem/cache/prefetch/queued.cc
@@ -439,7 +439,7 @@
     } else {
         // Add the translation request and try to resolve it later
         dpp.setTranslationRequest(translation_req);
- dpp.tc = cache->system->getThreadContext(translation_req->contextId());
+        dpp.tc = cache->system->threads[translation_req->contextId()];
         DPRINTF(HWPrefetch, "Prefetch queued with no translation. "
                 "addr:%#x priority: %3d\n", new_pfi.getAddr(), priority);
         addToQueue(pfqMissingTranslation, dpp);
diff --git a/src/sim/mem_state.cc b/src/sim/mem_state.cc
index f998fff..bfee9da 100644
--- a/src/sim/mem_state.cc
+++ b/src/sim/mem_state.cc
@@ -256,7 +256,7 @@
      * There is currently no general method across all TLB implementations
      * that can flush just part of the address space.
      */
-    for (auto tc : _ownerProcess->system->threadContexts) {
+    for (auto *tc: _ownerProcess->system->threads) {
         tc->getDTBPtr()->flushAll();
         tc->getITBPtr()->flushAll();
     }
@@ -358,7 +358,7 @@
      * There is currently no general method across all TLB implementations
      * that can flush just part of the address space.
      */
-    for (auto tc : _ownerProcess->system->threadContexts) {
+    for (auto *tc: _ownerProcess->system->threads) {
         tc->getDTBPtr()->flushAll();
         tc->getITBPtr()->flushAll();
     }
@@ -405,8 +405,7 @@
                  * ThreadContexts associated with this process.
                  */
                 for (auto &cid : _ownerProcess->contextIds) {
-                    ThreadContext *tc =
-                        _ownerProcess->system->getThreadContext(cid);
+                    auto *tc = _ownerProcess->system->threads[cid];
                     SETranslatingPortProxy
                         virt_mem(tc, SETranslatingPortProxy::Always);
                     vma.fillMemPages(vpage_start, _pageBytes, virt_mem);
diff --git a/src/sim/process.cc b/src/sim/process.cc
index 3fab853..28c0b54 100644
--- a/src/sim/process.cc
+++ b/src/sim/process.cc
@@ -293,7 +293,7 @@
fatal("Process %s is not associated with any HW contexts!\n", name());

     // first thread context for this process... initialize & enable
-    ThreadContext *tc = system->getThreadContext(contextIds[0]);
+    ThreadContext *tc = system->threads[contextIds[0]];

     // mark this context as active so it will start ticking.
     tc->activate();
diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc
index 2d87b05..41201ea 100644
--- a/src/sim/pseudo_inst.cc
+++ b/src/sim/pseudo_inst.cc
@@ -170,13 +170,13 @@
     DPRINTF(PseudoInst, "PseudoInst::wakeCPU(%i)\n", cpuid);
     System *sys = tc->getSystemPtr();

-    if (sys->numContexts() <= cpuid) {
+    if (sys->threads.size() <= cpuid) {
warn("PseudoInst::wakeCPU(%i), cpuid greater than number of contexts"
-             "(%i)\n",cpuid, sys->numContexts());
+             "(%i)\n", cpuid, sys->threads.size());
         return;
     }

-    ThreadContext *other_tc = sys->threadContexts[cpuid];
+    ThreadContext *other_tc = sys->threads[cpuid];
     if (other_tc->status() == ThreadContext::Suspended)
         other_tc->activate();
 }
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
index 6d39823..4a41609 100644
--- a/src/sim/syscall_emul.cc
+++ b/src/sim/syscall_emul.cc
@@ -119,9 +119,9 @@

     bool last_thread = true;
     Process *parent = nullptr, *tg_lead = nullptr;
-    for (int i = 0; last_thread && i < sys->numContexts(); i++) {
+    for (int i = 0; last_thread && i < sys->threads.size(); i++) {
         Process *walk;
-        if (!(walk = sys->threadContexts[i]->getProcessPtr()))
+        if (!(walk = sys->threads[i]->getProcessPtr()))
             continue;

         /**
@@ -133,8 +133,9 @@
         if (walk->pid() == p->tgid())
             tg_lead = walk;

-        if ((sys->threadContexts[i]->status() != ThreadContext::Halted) &&
-            (sys->threadContexts[i]->status() != ThreadContext::Halting) &&
+        auto *tc = sys->threads[i];
+        if ((tc->status() != ThreadContext::Halted) &&
+            (tc->status() != ThreadContext::Halting) &&
             (walk != p)) {
             /**
* Check if we share thread group with the pointer; this denotes
@@ -156,7 +157,7 @@
                  * all threads in the group.
                  */
                 if (*(p->exitGroup)) {
-                    sys->threadContexts[i]->halt();
+                    tc->halt();
                 } else {
                     last_thread = false;
                 }
@@ -201,7 +202,7 @@
      */
     int activeContexts = 0;
     for (auto &system: sys->systemList)
-        activeContexts += system->numRunningContexts();
+        activeContexts += system->threads.numRunning();

     if (activeContexts == 0) {
         /**
@@ -905,9 +906,9 @@
     System *sysh = tc->getSystemPtr();

     // Retrieves process pointer from active/suspended thread contexts.
-    for (int i = 0; i < sysh->numContexts(); i++) {
-        if (sysh->threadContexts[i]->status() != ThreadContext::Halted) {
-            Process *temp_h = sysh->threadContexts[i]->getProcessPtr();
+    for (auto *tc: sysh->threads) {
+        if (tc->status() != ThreadContext::Halted) {
+            Process *temp_h = tc->getProcessPtr();
             Process *walk_ph = (Process*)temp_h;

             if (walk_ph && walk_ph->pid() == process->pid())
diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh
index f2cc22c..aa81e14 100644
--- a/src/sim/syscall_emul.hh
+++ b/src/sim/syscall_emul.hh
@@ -1440,7 +1440,7 @@
         return -EINVAL;

     ThreadContext *ctc;
-    if (!(ctc = tc->getSystemPtr()->findFreeContext())) {
+    if (!(ctc = tc->getSystemPtr()->threads.findFree())) {
         DPRINTF_SYSCALL(Verbose, "clone: no spare thread context in system"
"[cpu %d, thread %d]", tc->cpuId(), tc->threadId());
         return -EAGAIN;
@@ -1861,7 +1861,7 @@
         break;

       case OS::TGT_RLIMIT_NPROC:
-        rlp->rlim_cur = rlp->rlim_max = tc->getSystemPtr()->numContexts();
+        rlp->rlim_cur = rlp->rlim_max = tc->getSystemPtr()->threads.size();
         rlp->rlim_cur = htog(rlp->rlim_cur, bo);
         rlp->rlim_max = htog(rlp->rlim_max, bo);
         break;
@@ -2198,8 +2198,8 @@

     System *sys = tc->getSystemPtr();
     Process *tgt_proc = nullptr;
-    for (int i = 0; i < sys->numContexts(); i++) {
-        Process *temp = sys->threadContexts[i]->getProcessPtr();
+    for (auto *tc: sys->threads) {
+        Process *temp = tc->getProcessPtr();
         if (temp->pid() == tid) {
             tgt_proc = temp;
             break;
diff --git a/src/sim/system.cc b/src/sim/system.cc
index 0bae99a..557ad7d 100644
--- a/src/sim/system.cc
+++ b/src/sim/system.cc
@@ -57,6 +57,7 @@
 #include "cpu/base.hh"
 #include "cpu/thread_context.hh"
 #include "debug/Loader.hh"
+#include "debug/Quiesce.hh"
 #include "debug/WorkItems.hh"
 #include "mem/abstract_mem.hh"
 #include "mem/physical.hh"
@@ -80,6 +81,68 @@

 vector<System *> System::systemList;

+ContextID
+System::Threads::insert(ThreadContext *tc, ContextID id)
+{
+    if (id == InvalidContextID) {
+        for (id = 0; id < size(); id++) {
+            if (!threads[id].context)
+                break;
+        }
+    }
+
+    if (id >= size())
+        threads.resize(id + 1);
+
+    fatal_if(threads[id].context,
+            "Cannot have two thread contexts with the same id (%d).", id);
+
+    auto &t = thread(id);
+    t.context = tc;
+#   if THE_ISA != NULL_ISA
+    int port = getRemoteGDBPort();
+    if (port) {
+        t.gdb = new RemoteGDB(tc->getSystemPtr(), tc, port + id);
+        t.gdb->listen();
+    }
+#   endif
+
+    return id;
+}
+
+void
+System::Threads::replace(ThreadContext *tc, ContextID id)
+{
+    auto &t = thread(id);
+    t.context = tc;
+    if (t.gdb)
+        t.gdb->replaceThreadContext(tc);
+}
+
+ThreadContext *
+System::Threads::findFree()
+{
+    for (auto &thread: threads) {
+        if (thread.context->status() == ThreadContext::Halted)
+            return thread.context;
+    }
+    return nullptr;
+}
+
+int
+System::Threads::numRunning() const
+{
+    int count = 0;
+    for (auto &thread: threads) {
+        auto status = thread.context->status();
+        if (status != ThreadContext::Halted &&
+                status != ThreadContext::Halting) {
+            count++;
+        }
+    }
+    return count;
+}
+
 int System::numSystemsRunning = 0;

 System::System(Params *p)
@@ -164,18 +227,13 @@
// Now that we're about to start simulation, wait for GDB connections if
     // requested.
 #if THE_ISA != NULL_ISA
-    for (auto *tc: threadContexts) {
-        auto *cpu = tc->getCpuPtr();
-        auto id = tc->contextId();
-        if (remoteGDB.size() <= id)
-            continue;
-        auto *rgdb = remoteGDB[id];
-
-        if (cpu->waitForRemoteGDB()) {
-            inform("%s: Waiting for a remote GDB connection on port %d.\n",
-                   cpu->name(), rgdb->port());
-
-            rgdb->connect();
+    for (int i = 0; i < threads.size(); i++) {
+        auto *gdb = threads.thread(i).gdb;
+        auto *cpu = threads[i]->getCpuPtr();
+        if (gdb && cpu->waitForRemoteGDB()) {
+            inform("%s: Waiting for a remote GDB connection on port %d.",
+                   cpu->name(), gdb->port());
+            gdb->connect();
         }
     }
 #endif
@@ -197,66 +255,31 @@

 bool System::breakpoint()
 {
-    if (remoteGDB.size())
-        return remoteGDB[0]->breakpoint();
-    return false;
+    if (!threads.size())
+        return false;
+    auto *gdb = threads.thread(0).gdb;
+    if (!gdb)
+        return false;
+    return gdb->breakpoint();
 }

 ContextID
 System::registerThreadContext(ThreadContext *tc, ContextID assigned)
 {
-    int id = assigned;
-    if (id == InvalidContextID) {
-        // Find an unused context ID for this thread.
-        id = 0;
-        while (id < threadContexts.size() && threadContexts[id])
-            id++;
-    }
+    ContextID id = threads.insert(tc, assigned);

-    if (threadContexts.size() <= id)
-        threadContexts.resize(id + 1);
-
-    fatal_if(threadContexts[id],
-             "Cannot have two CPUs with the same id (%d)\n", id);
-
-    threadContexts[id] = tc;
     for (auto *e: liveEvents)
         tc->schedule(e);

-#if THE_ISA != NULL_ISA
-    int port = getRemoteGDBPort();
-    if (port) {
-        RemoteGDB *rgdb = new RemoteGDB(this, tc, port + id);
-        rgdb->listen();
-
-        if (remoteGDB.size() <= id)
-            remoteGDB.resize(id + 1);
-
-        remoteGDB[id] = rgdb;
-    }
-#endif
-
-    activeCpus.push_back(false);
-
     return id;
 }

-ThreadContext *
-System::findFreeContext()
-{
-    for (auto &it : threadContexts) {
-        if (ThreadContext::Halted == it->status())
-            return it;
-    }
-    return nullptr;
-}
-
 bool
 System::schedule(PCEvent *event)
 {
     bool all = true;
     liveEvents.push_back(event);
-    for (auto *tc: threadContexts)
+    for (auto *tc: threads)
         all = tc->schedule(event) && all;
     return all;
 }
@@ -266,53 +289,35 @@
 {
     bool all = true;
     liveEvents.remove(event);
-    for (auto *tc: threadContexts)
+    for (auto *tc: threads)
         all = tc->remove(event) && all;
     return all;
 }

-int
-System::numRunningContexts()
-{
-    return std::count_if(
-        threadContexts.cbegin(),
-        threadContexts.cend(),
-        [] (ThreadContext* tc) {
-            return ((tc->status() != ThreadContext::Halted) &&
-                    (tc->status() != ThreadContext::Halting));
-        }
-    );
-}
-
 void
 System::replaceThreadContext(ThreadContext *tc, ContextID context_id)
 {
-    if (context_id >= threadContexts.size()) {
-        panic("replaceThreadContext: bad id, %d >= %d\n",
-              context_id, threadContexts.size());
-    }
+    auto *otc = threads[context_id];
+    threads.replace(tc, context_id);

     for (auto *e: liveEvents) {
-        threadContexts[context_id]->remove(e);
+        otc->remove(e);
         tc->schedule(e);
     }
-    threadContexts[context_id] = tc;
-    if (context_id < remoteGDB.size())
-        remoteGDB[context_id]->replaceThreadContext(tc);
 }

 bool
 System::validKvmEnvironment() const
 {
 #if USE_KVM
-    if (threadContexts.empty())
+    if (threads.empty())
         return false;

-    for (auto tc : threadContexts) {
-        if (dynamic_cast<BaseKvmCPU*>(tc->getCpuPtr()) == nullptr) {
+    for (auto *tc: threads) {
+        if (!dynamic_cast<BaseKvmCPU *>(tc->getCpuPtr()))
             return false;
-        }
     }
+
     return true;
 #else
     return false;
diff --git a/src/sim/system.hh b/src/sim/system.hh
index fa59765..530c5ea 100644
--- a/src/sim/system.hh
+++ b/src/sim/system.hh
@@ -52,6 +52,7 @@
 #include "base/loader/symtab.hh"
 #include "base/statistics.hh"
 #include "config/the_isa.hh"
+#include "cpu/base.hh"
 #include "cpu/pc_event.hh"
 #include "enums/MemoryMode.hh"
 #include "mem/mem_master.hh"
@@ -99,6 +100,123 @@

   public:

+    class Threads
+    {
+      private:
+        struct Thread
+        {
+            ThreadContext *context = nullptr;
+            bool active = false;
+            BaseRemoteGDB *gdb = nullptr;
+        };
+
+        std::vector<Thread> threads;
+
+        Thread &
+        thread(ContextID id)
+        {
+            assert(id < size());
+            return threads[id];
+        }
+
+        const Thread &
+        thread(ContextID id) const
+        {
+            assert(id < size());
+            return threads[id];
+        }
+
+        ContextID insert(ThreadContext *tc, ContextID id=InvalidContextID);
+        void replace(ThreadContext *tc, ContextID id);
+
+        friend class System;
+
+      public:
+        class const_iterator
+        {
+          private:
+            const Threads &threads;
+            int pos;
+
+            friend class Threads;
+
+            const_iterator(const Threads &_threads, int _pos) :
+                threads(_threads), pos(_pos)
+            {}
+
+          public:
+            const_iterator(const const_iterator &) = default;
+            const_iterator &operator = (const const_iterator &) = default;
+
+            using iterator_category = std::forward_iterator_tag;
+            using value_type = ThreadContext *;
+            using difference_type = int;
+            using pointer = const value_type *;
+            using reference = const value_type &;
+
+            const_iterator &
+            operator ++ ()
+            {
+                pos++;
+                return *this;
+            }
+
+            const_iterator
+            operator ++ (int)
+            {
+                return const_iterator(threads, pos++);
+            }
+
+            reference operator * () { return threads.thread(pos).context; }
+            pointer operator -> () { return &threads.thread(pos).context; }
+
+            bool
+            operator == (const const_iterator &other) const
+            {
+                return &threads == &other.threads && pos == other.pos;
+            }
+
+            bool
+            operator != (const const_iterator &other) const
+            {
+                return !(*this == other);
+            }
+        };
+
+        ThreadContext *findFree();
+
+        ThreadContext *
+        operator [](ContextID id) const
+        {
+            return thread(id).context;
+        }
+
+        void markActive(ContextID id) { thread(id).active = true; }
+
+        int size() const { return threads.size(); }
+        bool empty() const { return threads.empty(); }
+        int numRunning() const;
+        int
+        numActive() const
+        {
+            int count = 0;
+            for (auto &thread: threads) {
+                if (thread.active)
+                    count++;
+            }
+            return count;
+        }
+
+        void resume(ContextID id, Tick when);
+
+        const_iterator begin() const { return const_iterator(*this, 0); }
+ const_iterator end() const { return const_iterator(*this, size()); }
+    };
+
+    /**
+     * After all objects have been created and all ports are
+     * connected, check that the system port is connected.
+     */
     void init() override;
     void startup() override;

@@ -179,14 +297,7 @@
      */
     unsigned int cacheLineSize() const { return _cacheLineSize; }

-    std::vector<ThreadContext *> threadContexts;
-    ThreadContext *findFreeContext();
-
-    ThreadContext *
-    getThreadContext(ContextID tid) const
-    {
-        return threadContexts[tid];
-    }
+    Threads threads;

     const bool multiThread;

@@ -195,12 +306,6 @@
     bool schedule(PCEvent *event) override;
     bool remove(PCEvent *event) override;

-    unsigned numContexts() const { return threadContexts.size(); }
-
-    /** Return number of running (non-halted) thread contexts in
-     * system.  These threads could be Active or Suspended. */
-    int numRunningContexts();
-
     Addr pagePtr;

     uint64_t init_param;
@@ -288,7 +393,6 @@
     uint64_t workItemsBegin;
     uint64_t workItemsEnd;
     uint32_t numWorkIds;
-    std::vector<bool> activeCpus;

     /** This array is a per-system list of all devices capable of issuing a
      * memory system request and an associated string for each master id.
@@ -415,14 +519,8 @@
     int
     markWorkItem(int index)
     {
-        int count = 0;
-        assert(index < activeCpus.size());
-        activeCpus[index] = true;
-        for (std::vector<bool>::iterator i = activeCpus.begin();
-             i < activeCpus.end(); i++) {
-            if (*i) count++;
-        }
-        return count;
+        threads.markActive(index);
+        return threads.numActive();
     }

     inline void workItemBegin(uint32_t tid, uint32_t workid)
@@ -467,8 +565,8 @@
     /// @return Starting address of first page
     Addr allocPhysPages(int npages);

-    ContextID registerThreadContext(ThreadContext *tc,
-                                    ContextID assigned = InvalidContextID);
+    ContextID registerThreadContext(
+            ThreadContext *tc, ContextID assigned=InvalidContextID);
     void replaceThreadContext(ThreadContext *tc, ContextID context_id);

     void serialize(CheckpointOut &cp) const override;

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/25144
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: Idc4575c5a0b56fe75f5c497809ad91c22bfe26cc
Gerrit-Change-Number: 25144
Gerrit-PatchSet: 35
Gerrit-Owner: Gabe Black <gabebl...@google.com>
Gerrit-Reviewer: Alexandru Duțu <alexandru.d...@amd.com>
Gerrit-Reviewer: Bobby R. Bruce <bbr...@ucdavis.edu>
Gerrit-Reviewer: Brandon Potter <brandon.pot...@amd.com>
Gerrit-Reviewer: Gabe Black <gabebl...@google.com>
Gerrit-Reviewer: Giacomo Travaglini <giacomo.travagl...@arm.com>
Gerrit-Reviewer: Jason Lowe-Power <power...@gmail.com>
Gerrit-Reviewer: kokoro <noreply+kok...@google.com>
Gerrit-CC: Anthony Gutierrez <anthony.gutier...@amd.com>
Gerrit-MessageType: merged
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to