Metal: Prevent data race on mLastSubmittedCommands

There was a data-race between getting and using the pointer to
mLastSubmittedCommands in WaitForCommandsToBeScheduled and setting it
inside the scheduling handler.

Lock the mutex before calling waitUntilScheduled so that the object
doesn't get destroyed from underneath us.

Bug: chromium:1142024
Change-Id: Iadbf473530342de6d108d39285d723815452ac7c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/31260
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/metal/DeviceMTL.mm b/src/dawn_native/metal/DeviceMTL.mm
index 9bd4fea..3846d0d 100644
--- a/src/dawn_native/metal/DeviceMTL.mm
+++ b/src/dawn_native/metal/DeviceMTL.mm
@@ -357,7 +357,16 @@
 
     void Device::WaitForCommandsToBeScheduled() {
         SubmitPendingCommandBuffer();
-        [*mLastSubmittedCommands waitUntilScheduled];
+
+        // Only lock the object while we take a reference to it, otherwise we could block further
+        // progress if the driver calls the scheduled handler (which also acquires the lock) before
+        // finishing the waitUntilScheduled.
+        NSPRef<id<MTLCommandBuffer>> lastSubmittedCommands;
+        {
+            std::lock_guard<std::mutex> lock(mLastSubmittedCommandsMutex);
+            lastSubmittedCommands = mLastSubmittedCommands;
+        }
+        [*lastSubmittedCommands waitUntilScheduled];
     }
 
     MaybeError Device::WaitForIdleForDestruction() {