[dawn][tests] Updates operation waiting in general.

- Track last process event commands in the native EventManager to
  more accurately return whether there are further pending events
  after a ProcessEvent call.
- Removes extraneous ProcessEventCmd in wire client since the
  wire automatically includes that call now anyways.
- Adds a couple of additional entry points in wire related testing
  utils to allow for clearer operation waiting.
- Updates test fixture waiting helpers to utilize new helpers so
  that we can wait until all operations are complete including
  re-entrant callbacks.

Change-Id: Iaddb815bda4bf236bb770169c5b2c8d36967e474
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/190981
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
diff --git a/src/dawn/native/EventManager.cpp b/src/dawn/native/EventManager.cpp
index 7f49ee3..55dcf76 100644
--- a/src/dawn/native/EventManager.cpp
+++ b/src/dawn/native/EventManager.cpp
@@ -376,6 +376,13 @@
         if (!events->has_value()) {
             return;
         }
+        if (event->mCallbackMode != wgpu::CallbackMode::WaitAnyOnly) {
+            FutureID lastProcessedEventID = mLastProcessEventID.load(std::memory_order_acquire);
+            while (lastProcessedEventID < futureID &&
+                   !mLastProcessEventID.compare_exchange_weak(lastProcessedEventID, futureID,
+                                                              std::memory_order_acq_rel)) {
+            }
+        }
         (*events)->emplace(futureID, std::move(event));
     });
     return futureID;
@@ -462,13 +469,16 @@
         return readyEnd != futures.end();
     });
 
-    // Finally, call callbacks.
+    // Finally, call callbacks while comparing the last process event id with any new ones that may
+    // have been created via the callbacks.
+    FutureID lastProcessEventID = mLastProcessEventID.load(std::memory_order_acquire);
     for (auto& event : completable) {
         event->EnsureComplete(EventCompletionType::Ready);
     }
     // Note that in the event of all progressing events completing, but there exists non-progressing
     // events, we will return true one extra time.
-    return hasIncompleteEvents && hasProgressingEvents;
+    return hasIncompleteEvents && hasProgressingEvents &&
+           (lastProcessEventID != mLastProcessEventID.load(std::memory_order_acquire));
 }
 
 wgpu::WaitStatus EventManager::WaitAny(size_t count, FutureWaitInfo* infos, Nanoseconds timeout) {
diff --git a/src/dawn/native/EventManager.h b/src/dawn/native/EventManager.h
index 3f23374..0946708 100644
--- a/src/dawn/native/EventManager.h
+++ b/src/dawn/native/EventManager.h
@@ -88,13 +88,14 @@
     size_t mTimedWaitAnyMaxCount = kTimedWaitAnyMaxCountDefault;
     std::atomic<FutureID> mNextFutureID = 1;
 
-    // Only 1 thread is allowed to call ProcessEvents at a time. This lock ensures that.
-    std::mutex mProcessEventLock;
-
     // Freed once the user has dropped their last ref to the Instance, so can't call WaitAny or
     // ProcessEvents anymore. This breaks reference cycles.
     using EventMap = absl::flat_hash_map<FutureID, Ref<TrackedEvent>>;
     MutexProtected<std::optional<EventMap>> mEvents;
+
+    // Records last process event id in order to properly return whether or not there are still
+    // events to process when we have re-entrant callbacks.
+    std::atomic<FutureID> mLastProcessEventID = 0;
 };
 
 struct QueueAndSerial {
diff --git a/src/dawn/tests/DawnTest.cpp b/src/dawn/tests/DawnTest.cpp
index 55885b4..e6fdcbd 100644
--- a/src/dawn/tests/DawnTest.cpp
+++ b/src/dawn/tests/DawnTest.cpp
@@ -803,6 +803,10 @@
     queue = nullptr;
     device = nullptr;
     adapter = nullptr;
+
+    // Since the native instance is a global, we can't rely on it's destruction to clean up all
+    // callbacks. Instead, for each test, we make sure to clear all events.
+    WaitForAllOperations();
     instance = nullptr;
 
     // Since the native instance is a global, we can't rely on it's destruction to clean up all
@@ -1666,17 +1670,29 @@
 }
 
 void DawnTestBase::WaitForAllOperations() {
-    // Callback might be invoked on another thread that calls the same WaitABit() method, not
-    // necessarily the current thread. So we need to use atomic here.
-    std::atomic<bool> done(false);
-    device.GetQueue().OnSubmittedWorkDone(
-        [](WGPUQueueWorkDoneStatus, void* userdata) {
-            *static_cast<std::atomic<bool>*>(userdata) = true;
-        },
-        &done);
-    while (!done.load()) {
-        WaitABit();
+    // TODO: crbug.com/42241461 - This block should be removed once we have migrated all tests to
+    // use the new entry points.
+    if (device != nullptr) {
+        // Callback might be invoked on another thread that calls the same WaitABit() method, not
+        // necessarily the current thread. So we need to use atomic here.
+        std::atomic<bool> done(false);
+        device.GetQueue().OnSubmittedWorkDone(
+            [](WGPUQueueWorkDoneStatus, void* userdata) {
+                *static_cast<std::atomic<bool>*>(userdata) = true;
+            },
+            &done);
+        while (!done.load()) {
+            WaitABit();
+        }
     }
+
+    do {
+        FlushWire();
+        if (UsesWire() && instance != nullptr) {
+            instance.ProcessEvents();
+        }
+    } while (dawn::native::InstanceProcessEvents(gTestEnv->GetInstance()->Get()) ||
+             !mWireHelper->IsIdle());
 }
 
 DawnTestBase::ReadbackReservation DawnTestBase::ReserveReadback(wgpu::Device targetDevice,
diff --git a/src/dawn/tests/unittests/validation/BufferValidationTests.cpp b/src/dawn/tests/unittests/validation/BufferValidationTests.cpp
index f858e1d..d1b520f 100644
--- a/src/dawn/tests/unittests/validation/BufferValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/BufferValidationTests.cpp
@@ -191,7 +191,7 @@
     buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
 
     EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
-    WaitForAllOperations(device);
+    WaitForAllOperations();
 
     buf.Unmap();
 }
@@ -203,7 +203,7 @@
     buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
 
     EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
-    WaitForAllOperations(device);
+    WaitForAllOperations();
 
     buf.Unmap();
 }
@@ -331,7 +331,7 @@
     {
         wgpu::Buffer buffer = CreateMapReadBuffer(4);
         buffer.MapAsync(wgpu::MapMode::Read, 0, 4, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
     }
     {
@@ -341,7 +341,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(4);
         buffer.MapAsync(wgpu::MapMode::Write, 0, 4, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
     }
     {
@@ -363,7 +363,7 @@
         buffer.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, this + 1);
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, this))
             .Times(1);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 
     // Read + non-overlapping range
@@ -377,7 +377,7 @@
         buffer.MapAsync(wgpu::MapMode::Read, 8, 8, ToMockBufferMapAsyncCallback, this + 1);
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, this))
             .Times(1);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 
     // Write + overlapping range
@@ -391,7 +391,7 @@
         buffer.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, this + 1);
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, this))
             .Times(1);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 
     // Write + non-overlapping range
@@ -405,7 +405,7 @@
         buffer.MapAsync(wgpu::MapMode::Write, 8, 8, ToMockBufferMapAsyncCallback, this + 1);
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, this))
             .Times(1);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 }
 
@@ -435,7 +435,7 @@
         buf.Unmap();
 
         // The callback shouldn't be called again.
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
     {
         wgpu::Buffer buf = CreateMapWriteBuffer(4);
@@ -447,7 +447,7 @@
         buf.Unmap();
 
         // The callback shouldn't be called again.
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 }
 
@@ -466,7 +466,7 @@
         buf.MapAsync(wgpu::MapMode::Read, 8, 8, ToMockBufferMapAsyncCallback, this + 1);
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, this + 1))
             .Times(1);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
 
         // Check that only the second MapAsync had an effect
         ASSERT_EQ(nullptr, buf.GetConstMappedRange(0));
@@ -484,7 +484,7 @@
         buf.MapAsync(wgpu::MapMode::Write, 8, 8, ToMockBufferMapAsyncCallback, this + 1);
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, this + 1))
             .Times(1);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
 
         // Check that only the second MapAsync had an effect
         ASSERT_EQ(nullptr, buf.GetConstMappedRange(0));
@@ -504,7 +504,7 @@
         buf.Destroy();
 
         // The callback shouldn't be called again.
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
     {
         wgpu::Buffer buf = CreateMapWriteBuffer(4);
@@ -516,7 +516,7 @@
         buf.Destroy();
 
         // The callback shouldn't be called again.
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 }
 
@@ -529,7 +529,7 @@
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
             .WillOnce(InvokeWithoutArgs([&] { buf.Unmap(); }));
 
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
     {
         wgpu::Buffer buf = CreateMapWriteBuffer(4);
@@ -538,7 +538,7 @@
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
             .WillOnce(InvokeWithoutArgs([&] { buf.Unmap(); }));
 
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 }
 
@@ -551,7 +551,7 @@
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
             .WillOnce(InvokeWithoutArgs([&] { buf.Destroy(); }));
 
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
     {
         wgpu::Buffer buf = CreateMapWriteBuffer(4);
@@ -560,7 +560,7 @@
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
             .WillOnce(InvokeWithoutArgs([&] { buf.Destroy(); }));
 
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 }
 
@@ -582,9 +582,9 @@
             }));
 
         buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         // we need another wire flush to make the MapAsync in the callback to the server
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 }
 
@@ -605,9 +605,9 @@
         ASSERT_DEVICE_ERROR(
             buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr));
 
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         // we need another wire flush to make the MapAsync in the callback to the server
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 
     // Test MapAsync call in MapAsync Unmapped before callback callback
@@ -624,8 +624,8 @@
 
         buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
         buf.Unmap();
-        WaitForAllOperations(device);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
+        WaitForAllOperations();
     }
 
     // Test MapAsync call in MapAsync Destroyed before callback callback
@@ -644,8 +644,8 @@
 
         buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
         buf.Destroy();
-        WaitForAllOperations(device);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
+        WaitForAllOperations();
     }
 }
 
@@ -732,7 +732,7 @@
             EXPECT_EQ(WGPUBufferMapAsyncStatus_ValidationError, status);
         },
         nullptr));
-    WaitForAllOperations(device);
+    WaitForAllOperations();
 }
 
 // Test that it is valid to submit a buffer in a queue with a map usage if it is unmapped
@@ -773,7 +773,7 @@
         encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
         wgpu::CommandBuffer commands = encoder.Finish();
         ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
     {
         wgpu::Buffer bufA = device.CreateBuffer(&descriptorA);
@@ -785,7 +785,7 @@
         encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
         wgpu::CommandBuffer commands = encoder.Finish();
         ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
     {
         wgpu::BufferDescriptor mappedBufferDesc = descriptorA;
@@ -797,7 +797,7 @@
         encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
         wgpu::CommandBuffer commands = encoder.Finish();
         ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
     {
         wgpu::BufferDescriptor mappedBufferDesc = descriptorB;
@@ -809,7 +809,7 @@
         encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
         wgpu::CommandBuffer commands = encoder.Finish();
         ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 }
 
@@ -894,7 +894,7 @@
         buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
             .Times(1);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         buf.Unmap();
 
         ASSERT_EQ(nullptr, buf.GetMappedRange());
@@ -907,7 +907,7 @@
         buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
             .Times(1);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         buf.Unmap();
 
         ASSERT_EQ(nullptr, buf.GetMappedRange());
@@ -945,7 +945,7 @@
         buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
             .Times(1);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         buf.Destroy();
 
         ASSERT_EQ(nullptr, buf.GetMappedRange());
@@ -958,7 +958,7 @@
         buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
         EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
             .Times(1);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         buf.Destroy();
 
         ASSERT_EQ(nullptr, buf.GetMappedRange());
@@ -972,7 +972,7 @@
 
     buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
     EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
-    WaitForAllOperations(device);
+    WaitForAllOperations();
 
     ASSERT_EQ(nullptr, buf.GetMappedRange());
 }
@@ -991,7 +991,7 @@
         wgpu::Buffer buf = CreateMapReadBuffer(4);
 
         buf.MapAsync(wgpu::MapMode::Read, 0, 4, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
 
         ASSERT_NE(buf.GetConstMappedRange(), nullptr);
     }
@@ -1001,7 +1001,7 @@
         wgpu::Buffer buf = CreateMapWriteBuffer(4);
 
         buf.MapAsync(wgpu::MapMode::Write, 0, 4, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
 
         ASSERT_NE(buf.GetConstMappedRange(), nullptr);
         ASSERT_EQ(buf.GetConstMappedRange(), buf.GetMappedRange());
@@ -1062,7 +1062,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(8);
         buffer.MapAsync(wgpu::MapMode::Write, 0, 8, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_NE(buffer.GetMappedRange(0, 8), nullptr);
     }
 
@@ -1070,7 +1070,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(8);
         buffer.MapAsync(wgpu::MapMode::Write, 0, wgpu::kWholeMapSize, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_NE(buffer.GetMappedRange(0, 8), nullptr);
     }
 
@@ -1078,7 +1078,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(8);
         buffer.MapAsync(wgpu::MapMode::Write, 0, wgpu::kWholeMapSize, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_NE(buffer.GetMappedRange(0, wgpu::kWholeMapSize), nullptr);
     }
 
@@ -1086,7 +1086,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(8);
         buffer.MapAsync(wgpu::MapMode::Write, 0, 8, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_NE(buffer.GetMappedRange(8, 0), nullptr);
     }
 
@@ -1094,7 +1094,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(16);
         buffer.MapAsync(wgpu::MapMode::Write, 0, 16, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_NE(buffer.GetMappedRange(8, 4), nullptr);
     }
 
@@ -1102,7 +1102,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(8);
         buffer.MapAsync(wgpu::MapMode::Write, 0, 8, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(buffer.GetMappedRange(9, 0), nullptr);
         EXPECT_EQ(buffer.GetMappedRange(16, 0), nullptr);
         EXPECT_EQ(buffer.GetMappedRange(std::numeric_limits<size_t>::max(), 0), nullptr);
@@ -1112,7 +1112,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(16);
         buffer.MapAsync(wgpu::MapMode::Write, 8, 8, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(buffer.GetMappedRange(16, 4), nullptr);
         EXPECT_EQ(buffer.GetMappedRange(24, 0), nullptr);
         EXPECT_EQ(buffer.GetMappedRange(std::numeric_limits<size_t>::max(), 0), nullptr);
@@ -1122,7 +1122,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(12);
         buffer.MapAsync(wgpu::MapMode::Write, 0, 12, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(buffer.GetMappedRange(8, 5), nullptr);
         EXPECT_EQ(buffer.GetMappedRange(8, 8), nullptr);
     }
@@ -1131,7 +1131,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(12);
         buffer.MapAsync(wgpu::MapMode::Write, 0, 12, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         // set size to (max - 1) to avoid being equal to kWholeMapSize
         EXPECT_EQ(buffer.GetMappedRange(8, std::numeric_limits<size_t>::max() - 1), nullptr);
     }
@@ -1140,7 +1140,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(12);
         buffer.MapAsync(wgpu::MapMode::Write, 0, 8, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(buffer.GetMappedRange(0), nullptr);
     }
 
@@ -1148,7 +1148,7 @@
     {
         wgpu::Buffer buffer = CreateMapWriteBuffer(12);
         buffer.MapAsync(wgpu::MapMode::Write, 8, 4, nullptr, nullptr);
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(buffer.GetMappedRange(7, 4), nullptr);
         EXPECT_EQ(buffer.GetMappedRange(0, 4), nullptr);
         EXPECT_EQ(buffer.GetMappedRange(0, 12), nullptr);
@@ -1237,7 +1237,7 @@
             .Times(1);
         buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
         EXPECT_EQ(wgpu::BufferMapState::Pending, buf.GetMapState());
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(wgpu::BufferMapState::Mapped, buf.GetMapState());
         buf.Unmap();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
@@ -1254,7 +1254,7 @@
         EXPECT_EQ(wgpu::BufferMapState::Pending, buf.GetMapState());
         buf.Unmap();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
     }
 
@@ -1266,7 +1266,7 @@
             .Times(1);
         buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
         EXPECT_EQ(wgpu::BufferMapState::Pending, buf.GetMapState());
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(wgpu::BufferMapState::Mapped, buf.GetMapState());
         buf.Destroy();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
@@ -1283,7 +1283,7 @@
         EXPECT_EQ(wgpu::BufferMapState::Pending, buf.GetMapState());
         buf.Destroy();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
     }
 
@@ -1295,7 +1295,7 @@
             .Times(1);
         buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
         EXPECT_EQ(wgpu::BufferMapState::Pending, buf.GetMapState());
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(wgpu::BufferMapState::Mapped, buf.GetMapState());
         buf.Unmap();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
@@ -1312,7 +1312,7 @@
         EXPECT_EQ(wgpu::BufferMapState::Pending, buf.GetMapState());
         buf.Unmap();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
     }
 
@@ -1324,7 +1324,7 @@
             .Times(1);
         buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
         EXPECT_EQ(wgpu::BufferMapState::Pending, buf.GetMapState());
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(wgpu::BufferMapState::Mapped, buf.GetMapState());
         buf.Destroy();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
@@ -1341,7 +1341,7 @@
         EXPECT_EQ(wgpu::BufferMapState::Pending, buf.GetMapState());
         buf.Destroy();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
-        WaitForAllOperations(device);
+        WaitForAllOperations();
         EXPECT_EQ(wgpu::BufferMapState::Unmapped, buf.GetMapState());
     }
 
diff --git a/src/dawn/tests/unittests/validation/MultipleDeviceTests.cpp b/src/dawn/tests/unittests/validation/MultipleDeviceTests.cpp
index 14797af..c4d75ae 100644
--- a/src/dawn/tests/unittests/validation/MultipleDeviceTests.cpp
+++ b/src/dawn/tests/unittests/validation/MultipleDeviceTests.cpp
@@ -78,7 +78,7 @@
                                                      : wgpu::CallbackMode::AllowProcessEvents,
                                           creationCallback.Callback());
 
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 
     // CreateComputePipelineAsync errors if the shader module is created on a different device.
@@ -98,7 +98,7 @@
                                                      : wgpu::CallbackMode::AllowProcessEvents,
                                           creationCallback.Callback());
 
-        WaitForAllOperations(device);
+        WaitForAllOperations();
     }
 }
 
diff --git a/src/dawn/tests/unittests/validation/QueueOnSubmittedWorkDoneValidationTests.cpp b/src/dawn/tests/unittests/validation/QueueOnSubmittedWorkDoneValidationTests.cpp
index c0ae7a8..610fe22 100644
--- a/src/dawn/tests/unittests/validation/QueueOnSubmittedWorkDoneValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/QueueOnSubmittedWorkDoneValidationTests.cpp
@@ -58,5 +58,5 @@
     EXPECT_CALL(*mockQueueWorkDoneCallback, Call(WGPUQueueWorkDoneStatus_Success, this)).Times(1);
     device.GetQueue().OnSubmittedWorkDone(ToMockQueueWorkDone, this);
 
-    WaitForAllOperations(device);
+    WaitForAllOperations();
 }
diff --git a/src/dawn/tests/unittests/validation/ValidationTest.cpp b/src/dawn/tests/unittests/validation/ValidationTest.cpp
index 8256473..2472044 100644
--- a/src/dawn/tests/unittests/validation/ValidationTest.cpp
+++ b/src/dawn/tests/unittests/validation/ValidationTest.cpp
@@ -257,6 +257,15 @@
     EXPECT_TRUE(mWireHelper->FlushServer());
 }
 
+void ValidationTest::WaitForAllOperations() {
+    do {
+        FlushWire();
+        if (UsesWire()) {
+            instance.ProcessEvents();
+        }
+    } while (dawn::native::InstanceProcessEvents(mDawnInstance->Get()) || !mWireHelper->IsIdle());
+}
+
 void ValidationTest::WaitForAllOperations(const wgpu::Device& waitDevice) {
     bool done = false;
     waitDevice.GetQueue().OnSubmittedWorkDone(
diff --git a/src/dawn/tests/unittests/validation/ValidationTest.h b/src/dawn/tests/unittests/validation/ValidationTest.h
index 974770a..3485585 100644
--- a/src/dawn/tests/unittests/validation/ValidationTest.h
+++ b/src/dawn/tests/unittests/validation/ValidationTest.h
@@ -144,6 +144,10 @@
     bool UsesWire() const;
 
     void FlushWire();
+
+    // TODO: crbug.com/42241461 - Remove overload that passes a device once we update tests to use
+    // new entry points.
+    void WaitForAllOperations();
     void WaitForAllOperations(const wgpu::Device& device);
 
     // Helper functions to create objects to test validation.
diff --git a/src/dawn/utils/TerribleCommandBuffer.cpp b/src/dawn/utils/TerribleCommandBuffer.cpp
index 0b193e3..5defa5c 100644
--- a/src/dawn/utils/TerribleCommandBuffer.cpp
+++ b/src/dawn/utils/TerribleCommandBuffer.cpp
@@ -67,4 +67,8 @@
     return success;
 }
 
+bool TerribleCommandBuffer::Empty() {
+    return mOffset == 0;
+}
+
 }  // namespace dawn::utils
diff --git a/src/dawn/utils/TerribleCommandBuffer.h b/src/dawn/utils/TerribleCommandBuffer.h
index 493d941..8c6b72a 100644
--- a/src/dawn/utils/TerribleCommandBuffer.h
+++ b/src/dawn/utils/TerribleCommandBuffer.h
@@ -44,6 +44,7 @@
 
     void* GetCmdSpace(size_t size) override;
     bool Flush() override;
+    bool Empty();
 
   private:
     raw_ptr<dawn::wire::CommandHandler> mHandler = nullptr;
diff --git a/src/dawn/utils/WireHelper.cpp b/src/dawn/utils/WireHelper.cpp
index 3214c5a..63f96d7 100644
--- a/src/dawn/utils/WireHelper.cpp
+++ b/src/dawn/utils/WireHelper.cpp
@@ -118,6 +118,8 @@
 
     bool FlushServer() override { return true; }
 
+    bool IsIdle() override { return true; }
+
   private:
     const DawnProcTable& mProcs;
 };
@@ -187,6 +189,8 @@
 
     bool FlushServer() override { return mS2cBuf->Flush(); }
 
+    bool IsIdle() override { return mC2sBuf->Empty() && mS2cBuf->Empty(); }
+
   private:
     const DawnProcTable& mBackendProcs;
     std::unique_ptr<dawn::utils::TerribleCommandBuffer> mC2sBuf;
diff --git a/src/dawn/utils/WireHelper.h b/src/dawn/utils/WireHelper.h
index 7c02388..61b5903 100644
--- a/src/dawn/utils/WireHelper.h
+++ b/src/dawn/utils/WireHelper.h
@@ -69,6 +69,8 @@
 
     virtual bool FlushClient() = 0;
     virtual bool FlushServer() = 0;
+
+    virtual bool IsIdle() = 0;
 };
 
 std::unique_ptr<WireHelper> CreateWireHelper(const DawnProcTable& procs,
diff --git a/src/dawn/wire/client/Instance.cpp b/src/dawn/wire/client/Instance.cpp
index 82cd558..b63845b 100644
--- a/src/dawn/wire/client/Instance.cpp
+++ b/src/dawn/wire/client/Instance.cpp
@@ -262,24 +262,6 @@
 
 void Instance::ProcessEvents() {
     GetEventManager().ProcessPollEvents();
-
-    // TODO(crbug.com/dawn/1987): The responsibility of ProcessEvents here is a bit mixed. It both
-    // processes events coming in from the server, and also prompts the server to check for and
-    // forward over new events - which won't be received until *after* this client-side
-    // ProcessEvents completes.
-    //
-    // Fixing this nicely probably requires the server to more self-sufficiently
-    // forward the events, which is half of making the wire fully invisible to use (which we might
-    // like to do, someday, but not soon). This is easy for immediate events (like requestDevice)
-    // and thread-driven events (async pipeline creation), but harder for queue fences where we have
-    // to wait on the backend and then trigger Dawn code to forward the event.
-    //
-    // In the meantime, we could maybe do this on client->server flush to keep this concern in the
-    // wire instead of in the API itself, but otherwise it's not significantly better so we just
-    // keep it here for now for backward compatibility.
-    InstanceProcessEventsCmd cmd;
-    cmd.self = ToAPI(this);
-    GetClient()->SerializeCommand(cmd);
 }
 
 WGPUWaitStatus Instance::WaitAny(size_t count, WGPUFutureWaitInfo* infos, uint64_t timeoutNS) {