mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-06 13:15:59 +00:00
Fix leak of wire client default queue
Previously, deleting the device in the wire implicitly released all child objects. This is no longer the case, so a leak of the client default queue caused the service-side queue to leak. Fixed: chromium:1332926 Change-Id: I1efa02e79246f985e99e1bc814d87f292ddc22bd Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/92743 Reviewed-by: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
825b95b7c1
commit
3f1a93291b
@ -160,11 +160,10 @@ TEST_F(WireDisconnectTests, DeleteClientDestroysObjects) {
|
|||||||
|
|
||||||
DeleteClient();
|
DeleteClient();
|
||||||
|
|
||||||
// Expect release on all objects created by the client.
|
// Expect release on all objects created by the client. Note: the device
|
||||||
|
// should be deleted first because it may free its reference to the default queue
|
||||||
|
// on deletion.
|
||||||
Sequence s1, s2, s3;
|
Sequence s1, s2, s3;
|
||||||
EXPECT_CALL(api, QueueRelease(apiQueue)).Times(1).InSequence(s1);
|
|
||||||
EXPECT_CALL(api, CommandEncoderRelease(apiCommandEncoder)).Times(1).InSequence(s2);
|
|
||||||
EXPECT_CALL(api, SamplerRelease(apiSampler)).Times(1).InSequence(s3);
|
|
||||||
EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr))
|
EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr))
|
||||||
.Times(1)
|
.Times(1)
|
||||||
.InSequence(s1, s2);
|
.InSequence(s1, s2);
|
||||||
@ -175,6 +174,9 @@ TEST_F(WireDisconnectTests, DeleteClientDestroysObjects) {
|
|||||||
.Times(1)
|
.Times(1)
|
||||||
.InSequence(s1, s2);
|
.InSequence(s1, s2);
|
||||||
EXPECT_CALL(api, DeviceRelease(apiDevice)).Times(1).InSequence(s1, s2, s3);
|
EXPECT_CALL(api, DeviceRelease(apiDevice)).Times(1).InSequence(s1, s2, s3);
|
||||||
|
EXPECT_CALL(api, QueueRelease(apiQueue)).Times(1).InSequence(s1);
|
||||||
|
EXPECT_CALL(api, CommandEncoderRelease(apiCommandEncoder)).Times(1).InSequence(s2);
|
||||||
|
EXPECT_CALL(api, SamplerRelease(apiSampler)).Times(1).InSequence(s3);
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
|
||||||
// Signal that we already released and cleared callbacks for |apiDevice|
|
// Signal that we already released and cleared callbacks for |apiDevice|
|
||||||
|
@ -139,6 +139,60 @@ TEST_F(WireQueueTests, OnSubmittedWorkDoneInsideCallbackBeforeDisconnect) {
|
|||||||
GetWireClient()->Disconnect();
|
GetWireClient()->Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test releasing the default queue, then its device. Both should be
|
||||||
|
// released when the device is released since the device holds a reference
|
||||||
|
// to the queue. Regresssion test for crbug.com/1332926.
|
||||||
|
TEST_F(WireQueueTests, DefaultQueueThenDeviceReleased) {
|
||||||
|
// Note: The test fixture gets the default queue.
|
||||||
|
|
||||||
|
// Release the queue which is the last external client reference.
|
||||||
|
// The device still holds a reference.
|
||||||
|
wgpuQueueRelease(queue);
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
// Release the device which holds an internal reference to the queue.
|
||||||
|
// Now, the queue and device should be released on the server.
|
||||||
|
wgpuDeviceRelease(device);
|
||||||
|
|
||||||
|
EXPECT_CALL(api, QueueRelease(apiQueue));
|
||||||
|
EXPECT_CALL(api, DeviceRelease(apiDevice));
|
||||||
|
// These set X callback methods are called before the device is released.
|
||||||
|
EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr)).Times(1);
|
||||||
|
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, nullptr, nullptr)).Times(1);
|
||||||
|
EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(apiDevice, nullptr, nullptr)).Times(1);
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
// Indicate to the fixture that the device was already released.
|
||||||
|
DefaultApiDeviceWasReleased();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the device, then its default queue. The default queue should be
|
||||||
|
// released when its external reference is dropped since releasing the device
|
||||||
|
// drops the internal reference. Regresssion test for crbug.com/1332926.
|
||||||
|
TEST_F(WireQueueTests, DeviceThenDefaultQueueReleased) {
|
||||||
|
// Note: The test fixture gets the default queue.
|
||||||
|
|
||||||
|
// Release the device which holds an internal reference to the queue.
|
||||||
|
// Now, the should be released on the server, but not the queue since
|
||||||
|
// the default queue still has one external reference.
|
||||||
|
wgpuDeviceRelease(device);
|
||||||
|
|
||||||
|
EXPECT_CALL(api, DeviceRelease(apiDevice));
|
||||||
|
// These set X callback methods are called before the device is released.
|
||||||
|
EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr)).Times(1);
|
||||||
|
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, nullptr, nullptr)).Times(1);
|
||||||
|
EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(apiDevice, nullptr, nullptr)).Times(1);
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
// Release the external queue reference. The queue should be released.
|
||||||
|
wgpuQueueRelease(queue);
|
||||||
|
EXPECT_CALL(api, QueueRelease(apiQueue));
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
// Indicate to the fixture that the device was already released.
|
||||||
|
DefaultApiDeviceWasReleased();
|
||||||
|
}
|
||||||
|
|
||||||
// Only one default queue is supported now so we cannot test ~Queue triggering ClearAllCallbacks
|
// Only one default queue is supported now so we cannot test ~Queue triggering ClearAllCallbacks
|
||||||
// since it is always destructed after the test TearDown, and we cannot create a new queue obj
|
// since it is always destructed after the test TearDown, and we cannot create a new queue obj
|
||||||
// with wgpuDeviceGetQueue
|
// with wgpuDeviceGetQueue
|
||||||
|
@ -51,6 +51,19 @@ Client::~Client() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::DestroyAllObjects() {
|
void Client::DestroyAllObjects() {
|
||||||
|
// Free all devices first since they may hold references to other objects
|
||||||
|
// like the default queue. The Device destructor releases the default queue,
|
||||||
|
// which would be invalid if the queue was already freed.
|
||||||
|
while (!mObjects[ObjectType::Device].empty()) {
|
||||||
|
ObjectBase* object = mObjects[ObjectType::Device].head()->value();
|
||||||
|
|
||||||
|
DestroyObjectCmd cmd;
|
||||||
|
cmd.objectType = ObjectType::Device;
|
||||||
|
cmd.objectId = object->id;
|
||||||
|
SerializeCommand(cmd);
|
||||||
|
FreeObject(ObjectType::Device, object);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& objectList : mObjects) {
|
for (auto& objectList : mObjects) {
|
||||||
ObjectType objectType = static_cast<ObjectType>(&objectList - mObjects.data());
|
ObjectType objectType = static_cast<ObjectType>(&objectList - mObjects.data());
|
||||||
if (objectType == ObjectType::Device) {
|
if (objectType == ObjectType::Device) {
|
||||||
@ -66,16 +79,6 @@ void Client::DestroyAllObjects() {
|
|||||||
FreeObject(objectType, object);
|
FreeObject(objectType, object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!mObjects[ObjectType::Device].empty()) {
|
|
||||||
ObjectBase* object = mObjects[ObjectType::Device].head()->value();
|
|
||||||
|
|
||||||
DestroyObjectCmd cmd;
|
|
||||||
cmd.objectType = ObjectType::Device;
|
|
||||||
cmd.objectId = object->id;
|
|
||||||
SerializeCommand(cmd);
|
|
||||||
FreeObject(ObjectType::Device, object);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReservedTexture Client::ReserveTexture(WGPUDevice device) {
|
ReservedTexture Client::ReserveTexture(WGPUDevice device) {
|
||||||
|
@ -67,6 +67,10 @@ Device::~Device() {
|
|||||||
"Device destroyed before callback", request->userdata);
|
"Device destroyed before callback", request->userdata);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (mQueue != nullptr) {
|
||||||
|
GetProcs().queueRelease(ToAPI(mQueue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::GetLimits(WGPUSupportedLimits* limits) const {
|
bool Device::GetLimits(WGPUSupportedLimits* limits) const {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user