x86: Track message based interrupt cleanup functions in sender state.

This makes sure the completion function follows the packet, and allows
multiple packets to be in flight at once without the functions
overwritting each other.

Change-Id: Ic49c7b646d56b32c0453931942ee22ae07828bb6
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/26163
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Reviewed-by: Ayaz Akram <yazakram@ucdavis.edu>
Maintainer: Jason Lowe-Power <jason@lowepower.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/dev/x86/intdev.hh b/src/dev/x86/intdev.hh
index a40a1d4..a681a2e 100644
--- a/src/dev/x86/intdev.hh
+++ b/src/dev/x86/intdev.hh
@@ -45,6 +45,7 @@
 #include <functional>
 #include <string>
 
+#include "base/cast.hh"
 #include "mem/tport.hh"
 #include "sim/sim_object.hh"
 
@@ -103,7 +104,11 @@
     Tick latency;
 
     typedef std::function<void(PacketPtr)> OnCompletionFunc;
-    OnCompletionFunc onCompletion = nullptr;
+    struct OnCompletion : public Packet::SenderState
+    {
+        OnCompletionFunc func;
+        OnCompletion(OnCompletionFunc _func) : func(_func) {}
+    };
     // If nothing extra needs to happen, just clean up the packet.
     static void defaultOnCompletion(PacketPtr pkt) { delete pkt; }
 
@@ -120,8 +125,9 @@
     recvTimingResp(PacketPtr pkt) override
     {
         assert(pkt->isResponse());
-        onCompletion(pkt);
-        onCompletion = nullptr;
+        auto *oc = safe_cast<OnCompletion *>(pkt->popSenderState());
+        oc->func(pkt);
+        delete oc;
         return true;
     }
 
@@ -130,7 +136,7 @@
             OnCompletionFunc func=defaultOnCompletion)
     {
         if (timing) {
-            onCompletion = func;
+            pkt->pushSenderState(new OnCompletion(func));
             schedTimingReq(pkt, curTick() + latency);
             // The target handles cleaning up the packet in timing mode.
         } else {