Use smart Refs for IOKit and CoreFoundation objects.

Bug: dawn:89
Change-Id: Idea634bcc65ab4ec017f4e4c2431e95915f533df
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/32661
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Corentin Wallez 2020-11-17 11:35:11 +00:00 committed by Commit Bot service account
parent f2bc3b3edd
commit d98e8b70bb
7 changed files with 132 additions and 18 deletions

View File

@ -157,11 +157,13 @@ if (is_win || is_linux || is_chromeos || is_mac || is_fuchsia || is_android) {
"BitSetIterator.h", "BitSetIterator.h",
"Compiler.h", "Compiler.h",
"Constants.h", "Constants.h",
"CoreFoundationRef.h",
"DynamicLib.cpp", "DynamicLib.cpp",
"DynamicLib.h", "DynamicLib.h",
"GPUInfo.cpp", "GPUInfo.cpp",
"GPUInfo.h", "GPUInfo.h",
"HashUtils.h", "HashUtils.h",
"IOKitRef.h",
"LinkedList.h", "LinkedList.h",
"Log.cpp", "Log.cpp",
"Log.h", "Log.h",

View File

@ -19,11 +19,13 @@ target_sources(dawn_common PRIVATE
"BitSetIterator.h" "BitSetIterator.h"
"Compiler.h" "Compiler.h"
"Constants.h" "Constants.h"
"CoreFoundationRef.h"
"DynamicLib.cpp" "DynamicLib.cpp"
"DynamicLib.h" "DynamicLib.h"
"GPUInfo.cpp" "GPUInfo.cpp"
"GPUInfo.h" "GPUInfo.h"
"HashUtils.h" "HashUtils.h"
"IOKitRef.h"
"LinkedList.h" "LinkedList.h"
"Log.cpp" "Log.cpp"
"Log.h" "Log.h"

View File

@ -0,0 +1,46 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COMMON_COREFOUNDATIONREF_H_
#define COMMON_COREFOUNDATIONREF_H_
#include "common/RefBase.h"
#include <CoreFoundation/CoreFoundation.h>
template <typename T>
struct CoreFoundationRefTraits {
static constexpr T kNullValue = nullptr;
static void Reference(T value) {
CFRetain(value);
}
static void Release(T value) {
CFRelease(value);
}
};
template <typename T>
class CFRef : public RefBase<T, CoreFoundationRefTraits<T>> {
public:
using RefBase<T, CoreFoundationRefTraits<T>>::RefBase;
};
template <typename T>
CFRef<T> AcquireCFRef(T pointee) {
CFRef<T> ref;
ref.Acquire(pointee);
return ref;
}
#endif // COMMON_COREFOUNDATIONREF_H_

46
src/common/IOKitRef.h Normal file
View File

@ -0,0 +1,46 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COMMON_IOKITREF_H_
#define COMMON_IOKITREF_H_
#include "common/RefBase.h"
#include <IOKit/IOKitLib.h>
template <typename T>
struct IOKitRefTraits {
static constexpr T kNullValue = IO_OBJECT_NULL;
static void Reference(T value) {
IOObjectRetain(value);
}
static void Release(T value) {
IOObjectRelease(value);
}
};
template <typename T>
class IORef : public RefBase<T, IOKitRefTraits<T>> {
public:
using RefBase<T, IOKitRefTraits<T>>::RefBase;
};
template <typename T>
IORef<T> AcquireIORef(T pointee) {
IORef<T> ref;
ref.Acquire(pointee);
return ref;
}
#endif // COMMON_IOKITREF_H_

View File

@ -15,6 +15,7 @@
#ifndef COMMON_REFBASE_H_ #ifndef COMMON_REFBASE_H_
#define COMMON_REFBASE_H_ #define COMMON_REFBASE_H_
#include "common/Assert.h"
#include "common/Compiler.h" #include "common/Compiler.h"
#include <type_traits> #include <type_traits>
@ -163,6 +164,11 @@ class RefBase {
mValue = value; mValue = value;
} }
T* InitializeInto() DAWN_NO_DISCARD {
ASSERT(mValue == kNullValue);
return &mValue;
}
private: private:
// Friend is needed so that instances of RefBase<U> can call Reference and Release on // Friend is needed so that instances of RefBase<U> can call Reference and Release on
// RefBase<T>. // RefBase<T>.

View File

@ -14,6 +14,7 @@
#include "dawn_native/metal/BackendMTL.h" #include "dawn_native/metal/BackendMTL.h"
#include "common/CoreFoundationRef.h"
#include "common/GPUInfo.h" #include "common/GPUInfo.h"
#include "common/NSRef.h" #include "common/NSRef.h"
#include "common/Platform.h" #include "common/Platform.h"
@ -23,6 +24,7 @@
#if defined(DAWN_PLATFORM_MACOS) #if defined(DAWN_PLATFORM_MACOS)
# import <IOKit/IOKitLib.h> # import <IOKit/IOKitLib.h>
# include "common/IOKitRef.h"
#endif #endif
namespace dawn_native { namespace metal { namespace dawn_native { namespace metal {
@ -72,18 +74,17 @@ namespace dawn_native { namespace metal {
// Recursively search registry entry and its parents for property name // Recursively search registry entry and its parents for property name
// The data should release with CFRelease // The data should release with CFRelease
CFDataRef data = static_cast<CFDataRef>(IORegistryEntrySearchCFProperty( CFRef<CFDataRef> data =
entry, kIOServicePlane, name, kCFAllocatorDefault, AcquireCFRef(static_cast<CFDataRef>(IORegistryEntrySearchCFProperty(
kIORegistryIterateRecursively | kIORegistryIterateParents)); entry, kIOServicePlane, name, kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents)));
if (data == nullptr) { if (data == nullptr) {
return value; return value;
} }
// CFDataGetBytePtr() is guaranteed to return a read-only pointer // CFDataGetBytePtr() is guaranteed to return a read-only pointer
value = *reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(data)); value = *reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(data.Get()));
CFRelease(data);
return value; return value;
} }
@ -107,38 +108,35 @@ namespace dawn_native { namespace metal {
MaybeError API_AVAILABLE(macos(10.13)) MaybeError API_AVAILABLE(macos(10.13))
GetDeviceIORegistryPCIInfo(id<MTLDevice> device, PCIIDs* ids) { GetDeviceIORegistryPCIInfo(id<MTLDevice> device, PCIIDs* ids) {
// Get a matching dictionary for the IOGraphicsAccelerator2 // Get a matching dictionary for the IOGraphicsAccelerator2
CFMutableDictionaryRef matchingDict = IORegistryEntryIDMatching([device registryID]); CFRef<CFMutableDictionaryRef> matchingDict =
AcquireCFRef(IORegistryEntryIDMatching([device registryID]));
if (matchingDict == nullptr) { if (matchingDict == nullptr) {
return DAWN_INTERNAL_ERROR("Failed to create the matching dict for the device"); return DAWN_INTERNAL_ERROR("Failed to create the matching dict for the device");
} }
// IOServiceGetMatchingService will consume the reference on the matching dictionary, // IOServiceGetMatchingService will consume the reference on the matching dictionary,
// so we don't need to release the dictionary. // so we don't need to release the dictionary.
io_registry_entry_t acceleratorEntry = IORef<io_registry_entry_t> acceleratorEntry = AcquireIORef(
IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict); IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict.Detach()));
if (acceleratorEntry == IO_OBJECT_NULL) { if (acceleratorEntry == IO_OBJECT_NULL) {
return DAWN_INTERNAL_ERROR( return DAWN_INTERNAL_ERROR(
"Failed to get the IO registry entry for the accelerator"); "Failed to get the IO registry entry for the accelerator");
} }
// Get the parent entry that will be the IOPCIDevice // Get the parent entry that will be the IOPCIDevice
io_registry_entry_t deviceEntry = IO_OBJECT_NULL; IORef<io_registry_entry_t> deviceEntry;
if (IORegistryEntryGetParentEntry(acceleratorEntry, kIOServicePlane, &deviceEntry) != if (IORegistryEntryGetParentEntry(acceleratorEntry.Get(), kIOServicePlane,
kIOReturnSuccess) { deviceEntry.InitializeInto()) != kIOReturnSuccess) {
IOObjectRelease(acceleratorEntry);
return DAWN_INTERNAL_ERROR("Failed to get the IO registry entry for the device"); return DAWN_INTERNAL_ERROR("Failed to get the IO registry entry for the device");
} }
ASSERT(deviceEntry != IO_OBJECT_NULL); ASSERT(deviceEntry != IO_OBJECT_NULL);
IOObjectRelease(acceleratorEntry);
uint32_t vendorId = GetEntryProperty(deviceEntry, CFSTR("vendor-id")); uint32_t vendorId = GetEntryProperty(deviceEntry.Get(), CFSTR("vendor-id"));
uint32_t deviceId = GetEntryProperty(deviceEntry, CFSTR("device-id")); uint32_t deviceId = GetEntryProperty(deviceEntry.Get(), CFSTR("device-id"));
*ids = PCIIDs{vendorId, deviceId}; *ids = PCIIDs{vendorId, deviceId};
IOObjectRelease(deviceEntry);
return {}; return {};
} }

View File

@ -402,3 +402,17 @@ TEST(Ref, MoveAssignmentDerived) {
destination = nullptr; destination = nullptr;
EXPECT_TRUE(deleted); EXPECT_TRUE(deleted);
} }
// Test Ref's InitializeInto.
TEST(Ref, InitializeInto) {
bool deleted = false;
RCTest* original = new RCTest(&deleted);
// InitializeInto acquires the ref.
Ref<RCTest> ref;
*ref.InitializeInto() = original;
EXPECT_EQ(original->GetRefCountForTesting(), 1u);
ref = nullptr;
EXPECT_TRUE(deleted);
}