[wire] Fix potential lock inversion in buffer mapping.

- The potential lock inversion was introduced in
  https://dawn-review.git.corp.google.com/c/dawn/+/317816. This
  change ensures that the inversion can no longer occur.

Bug: 529413629
Change-Id: I848b68630e951d642eaf5175d39b7a02cd29d902
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/321995
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
diff --git a/src/dawn/wire/client/Buffer.cpp b/src/dawn/wire/client/Buffer.cpp
index fcfebbd..df97863 100644
--- a/src/dawn/wire/client/Buffer.cpp
+++ b/src/dawn/wire/client/Buffer.cpp
@@ -315,27 +315,29 @@
 }
 
 void Buffer::WillDropLastExternalRef() {
-    mState.Use([this](auto state) {
-        SetFutureStatus(state, WGPUMapAsyncStatus_Aborted,
-                        "Buffer was destroyed before mapping was resolved.");
-    });
+    SetFutureStatus(WGPUMapAsyncStatus_Aborted,
+                    "Buffer was destroyed before mapping was resolved.");
 }
 
 ObjectType Buffer::GetObjectType() const {
     return ObjectType::Buffer;
 }
 
-void Buffer::SetFutureStatus(GuardedState& state,
-                             WGPUMapAsyncStatus status,
-                             std::string_view message) {
-    if (!state->pendingMapRequest) {
+void Buffer::SetFutureStatus(WGPUMapAsyncStatus status, std::string_view message) {
+    auto futureID = mState.Use([&](auto state) -> std::optional<FutureID> {
+        if (!state->pendingMapRequest) {
+            return std::nullopt;
+        }
+
+        FutureID result = state->pendingMapRequest->futureID;
+        state->pendingMapRequest = std::nullopt;
+        return result;
+    });
+
+    if (!futureID) {
         return;
     }
-
-    FutureID futureID = state->pendingMapRequest->futureID;
-    state->pendingMapRequest = std::nullopt;
-
-    auto wireStatus = GetEventManager().SetFutureReady<MapAsyncEvent>(futureID, status,
+    auto wireStatus = GetEventManager().SetFutureReady<MapAsyncEvent>(*futureID, status,
                                                                       ToOutputStringView(message));
     DAWN_CHECK(wireStatus == WireResult::Success);
 }
@@ -353,9 +355,6 @@
 
     bool success = mState.Use([&](auto state) {
         if (state->pendingMapRequest) {
-            [[maybe_unused]] auto id = GetEventManager().SetFutureReady<MapAsyncEvent>(
-                futureIDInternal, WGPUMapAsyncStatus_Error,
-                ToOutputStringView("Buffer already has an outstanding map pending."));
             return false;
         }
 
@@ -380,6 +379,9 @@
         return true;
     });
     if (!success) {
+        [[maybe_unused]] auto id = GetEventManager().SetFutureReady<MapAsyncEvent>(
+            futureIDInternal, WGPUMapAsyncStatus_Error,
+            ToOutputStringView("Buffer already has an outstanding map pending."));
         return {futureIDInternal};
     }
 
@@ -508,11 +510,10 @@
         state->mappedState = MapState::Unmapped;
         state->mappedOffset = 0;
         state->mappedSize = 0;
-
-        SetFutureStatus(state, WGPUMapAsyncStatus_Aborted,
-                        "Buffer was unmapped before mapping was resolved.");
     });
 
+    SetFutureStatus(WGPUMapAsyncStatus_Aborted, "Buffer was unmapped before mapping was resolved.");
+
     BufferUnmapCmd cmd{};
     cmd.self = ToAPI(this);
     client->SerializeCommand(cmd);
@@ -523,10 +524,10 @@
 
     // Remove the current mapping and destroy MemoryHandle.
     mState.Use([&](auto state) {
-        SetFutureStatus(state, WGPUMapAsyncStatus_Aborted,
-                        "Buffer was destroyed before mapping was resolved.");
         FreeMappedData(state);
     });
+    SetFutureStatus(WGPUMapAsyncStatus_Aborted,
+                    "Buffer was destroyed before mapping was resolved.");
 
     BufferDestroyCmd cmd{};
     cmd.self = ToAPI(this);
diff --git a/src/dawn/wire/client/Buffer.h b/src/dawn/wire/client/Buffer.h
index ccacc8c..a2d5dbd 100644
--- a/src/dawn/wire/client/Buffer.h
+++ b/src/dawn/wire/client/Buffer.h
@@ -116,8 +116,8 @@
 
     void WillDropLastExternalRef() override;
 
-    // Prepares the callbacks to be called and potentially calls them
-    void SetFutureStatus(GuardedState& state, WGPUMapAsyncStatus status, std::string_view message);
+    // Prepares the callbacks to be called and potentially calls them.
+    void SetFutureStatus(WGPUMapAsyncStatus status, std::string_view message);
 
     void FreeMappedData(GuardedState& state);