From b6c8649cbf562985478177de6cae56d80701e203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 14:47:30 +0800 Subject: [PATCH] macOS: improve IO service related code generally --- src/detection/battery/battery_apple.c | 29 +++------- src/detection/brightness/brightness_apple.c | 25 ++++---- src/detection/cpu/cpu_apple.c | 56 ++++++++---------- src/detection/diskio/diskio_apple.c | 12 +--- src/detection/gpu/gpu_apple.c | 8 +-- src/detection/host/host_apple.c | 25 +++----- .../physicaldisk/physicaldisk_apple.c | 12 +--- src/detection/temps/temps_apple.c | 28 ++++----- src/util/apple/cf_helpers.c | 57 ++++++++++--------- src/util/apple/cf_helpers.h | 11 +++- 10 files changed, 108 insertions(+), 155 deletions(-) diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c index 63c5654be..c0d0ec8a6 100644 --- a/src/detection/battery/battery_apple.c +++ b/src/detection/battery/battery_apple.c @@ -8,22 +8,19 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) { - io_iterator_t iterator; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess) + FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL; + if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess) return "IOServiceGetMatchingServices() failed"; io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryBattery = registryEntry; FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef properties = NULL; - if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) - { - IOObjectRelease(registryEntry); + if (IORegistryEntryCreateCFProperties(entryBattery, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) continue; - } bool boolValue; - const char* error; FFBatteryResult* battery = ffListAdd(results); battery->temperature = FF_BATTERY_TEMP_UNSET; @@ -36,15 +33,11 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) int currentCapacity, maxCapacity; - if ((error = ffCfDictGetInt(properties, CFSTR(kIOPMPSMaxCapacityKey), &maxCapacity))) - return error; - if (maxCapacity <= 0) - return "Querying MaxCapacity failed"; + if (ffCfDictGetInt(properties, CFSTR(kIOPMPSMaxCapacityKey), &maxCapacity) != NULL || maxCapacity <= 0) + continue; - if ((error = ffCfDictGetInt(properties, CFSTR(kIOPMPSCurrentCapacityKey), ¤tCapacity))) - return error; - if(currentCapacity <= 0) - return "Querying CurrentCapacity failed"; + if (ffCfDictGetInt(properties, CFSTR(kIOPMPSCurrentCapacityKey), ¤tCapacity) != NULL || currentCapacity <= 0) + continue; battery->capacity = currentCapacity * 100.0 / maxCapacity; @@ -82,11 +75,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) else ffDetectSmcTemps(FF_TEMP_BATTERY, &battery->temperature); } - - IOObjectRelease(registryEntry); } - IOObjectRelease(iterator); - return NULL; } diff --git a/src/detection/brightness/brightness_apple.c b/src/detection/brightness/brightness_apple.c index 52b0cee32..a9f8daf0c 100644 --- a/src/detection/brightness/brightness_apple.c +++ b/src/detection/brightness/brightness_apple.c @@ -57,38 +57,35 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult* if (!IOAVServiceCreate || !IOAVServiceReadI2C) return "IOAVService is not available"; - io_iterator_t iterator; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("DCPAVServiceProxy"), &iterator) != kIOReturnSuccess) + FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL; + if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("DCPAVServiceProxy"), &iterator) != kIOReturnSuccess) return "IOServiceGetMatchingServices() failed"; io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { + FF_CFTYPE_AUTO_RELEASE IOAVServiceRef service = NULL; { - FF_CFTYPE_AUTO_RELEASE CFBooleanRef IOAVServiceUserInterfaceSupported = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("IOAVServiceUserInterfaceSupported"), kCFAllocatorDefault, kNilOptions); + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryAv = registryEntry; + + FF_CFTYPE_AUTO_RELEASE CFBooleanRef IOAVServiceUserInterfaceSupported = IORegistryEntryCreateCFProperty(entryAv, CFSTR("IOAVServiceUserInterfaceSupported"), kCFAllocatorDefault, kNilOptions); if (IOAVServiceUserInterfaceSupported && !CFBooleanGetValue(IOAVServiceUserInterfaceSupported)) { // IOAVServiceCreateWithService won't work - IOObjectRelease(registryEntry); continue; } - } - { - FF_CFTYPE_AUTO_RELEASE CFStringRef location = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("Location"), kCFAllocatorDefault, kNilOptions); + FF_CFTYPE_AUTO_RELEASE CFStringRef location = IORegistryEntryCreateCFProperty(entryAv, CFSTR("Location"), kCFAllocatorDefault, kNilOptions); if (location && CFStringCompare(location, CFSTR("Embedded"), 0) == 0) { // Builtin display should be handled by DisplayServices - IOObjectRelease(registryEntry); continue; } + + service = IOAVServiceCreateWithService(kCFAllocatorDefault, (io_service_t) registryEntry); + if (!service) continue; } - FF_CFTYPE_AUTO_RELEASE IOAVServiceRef service = IOAVServiceCreateWithService(kCFAllocatorDefault, (io_service_t) registryEntry); - IOObjectRelease(registryEntry); - - if (!service) continue; - { uint8_t i2cIn[4] = { 0x82, 0x01, 0x10 /* luminance */ }; i2cIn[3] = 0x6e ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2]; diff --git a/src/detection/cpu/cpu_apple.c b/src/detection/cpu/cpu_apple.c index a0afaa697..2f3ec2de7 100644 --- a/src/detection/cpu/cpu_apple.c +++ b/src/detection/cpu/cpu_apple.c @@ -1,6 +1,7 @@ #include "cpu.h" #include "common/sysctl.h" #include "detection/temps/temps_apple.h" +#include "util/stringUtils.h" static double detectCpuTemp(const FFstrbuf* cpuName) { @@ -35,44 +36,33 @@ static const char* detectFrequency(FFCPUResult* cpu) { // https://github.com/giampaolo/psutil/pull/2222/files - io_iterator_t iterator; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleARMIODevice"), &iterator) != kIOReturnSuccess) + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceNameMatching("pmgr")); + if (!entryDevice) return "IOServiceGetMatchingServices() failed"; - io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + if (!IOObjectConformsTo(entryDevice, "AppleARMIODevice")) + return "\"pmgr\" should conform to \"AppleARMIODevice\""; + + FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef properties = NULL; + if (IORegistryEntryCreateCFProperties(entryDevice, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) + return "IORegistryEntryCreateCFProperties() failed"; + + uint32_t pMin, eMin, aMax, pCoreLength; + if (ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), 0, 4, (uint8_t*) &pMin, &pCoreLength) != NULL) // pCore + return "\"voltage-states5-sram\" in \"pmgr\" is not found"; + if (ffCfDictGetData(properties, CFSTR("voltage-states1-sram"), 0, 4, (uint8_t*) &eMin, NULL) != NULL) // eCore + return "\"voltage-states1-sram\" in \"pmgr\" is not found"; + + cpu->frequencyMin = (pMin < eMin ? pMin : eMin) / (1000.0 * 1000 * 1000); + + if (pCoreLength >= 8) { - CFMutableDictionaryRef properties; - if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) - { - IOObjectRelease(registryEntry); - continue; - } - - io_name_t name; - if (IORegistryEntryGetName(registryEntry, name) != KERN_SUCCESS) - continue; - if (strcmp(name, "pmgr") != 0) - continue; - - uint32_t pMin, eMin, aMax, pCoreLength; - ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), 0, 4, (uint8_t*) &pMin, &pCoreLength); // pCore - ffCfDictGetData(properties, CFSTR("voltage-states1-sram"), 0, 4, (uint8_t*) &eMin, NULL); // eCore - cpu->frequencyMin = (pMin < eMin ? pMin : eMin) / (1000.0 * 1000 * 1000); - - if (pCoreLength >= 8) - { - ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), pCoreLength - 8, 4, (uint8_t*) &aMax, NULL); - cpu->frequencyMax = aMax / (1000.0 * 1000 * 1000); - } - else - cpu->frequencyMax = 0.0; - - CFRelease(properties); - IOObjectRelease(registryEntry); + ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), pCoreLength - 8, 4, (uint8_t*) &aMax, NULL); + cpu->frequencyMax = aMax / (1000.0 * 1000 * 1000); } + else + cpu->frequencyMax = 0.0; - IOObjectRelease(iterator); return NULL; } #else diff --git a/src/detection/diskio/diskio_apple.c b/src/detection/diskio/diskio_apple.c index bc5d57f25..2e202f3d9 100644 --- a/src/detection/diskio/diskio_apple.c +++ b/src/detection/diskio/diskio_apple.c @@ -8,22 +8,14 @@ #include #include -static inline void wrapIoObjectRelease(io_service_t* service) -{ - assert(service); - if (*service) - IOObjectRelease(*service); -} -#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease))) - const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) { FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = 0; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS) + if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS) return "IOServiceGetMatchingServices() failed"; io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryPartition = registryEntry; diff --git a/src/detection/gpu/gpu_apple.c b/src/detection/gpu/gpu_apple.c index b7db8c562..6113dfce6 100644 --- a/src/detection/gpu/gpu_apple.c +++ b/src/detection/gpu/gpu_apple.c @@ -38,12 +38,12 @@ static double detectGpuTemp(const FFstrbuf* gpuName) const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) { - io_iterator_t iterator; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOAcceleratorClassName), &iterator) != kIOReturnSuccess) + FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL; + if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOAcceleratorClassName), &iterator) != kIOReturnSuccess) return "IOServiceGetMatchingServices() failed"; io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { CFMutableDictionaryRef properties; if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) @@ -106,8 +106,6 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) IOObjectRelease(registryEntry); } - IOObjectRelease(iterator); - ffGpuDetectMetal(gpus); return NULL; } diff --git a/src/detection/host/host_apple.c b/src/detection/host/host_apple.c index 6f5184e50..07f1cd102 100644 --- a/src/detection/host/host_apple.c +++ b/src/detection/host/host_apple.c @@ -169,26 +169,15 @@ static const char* getProductNameWithHwModel(const FFstrbuf* hwModel) const char* getProductNameWithIokit(FFstrbuf* result) { - io_iterator_t iterator; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceNameMatching("product"), &iterator) != kIOReturnSuccess) - return "IOServiceGetMatchingServices() failed"; + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t registryEntry = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceNameMatching("product")); + if (!registryEntry) + return "IOServiceGetMatchingService() failed"; - io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) - { - FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef properties = NULL; - if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) - { - IOObjectRelease(registryEntry); - continue; - } + FF_CFTYPE_AUTO_RELEASE CFStringRef productName = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("product-name"), kCFAllocatorDefault, kNilOptions); + if (!productName) + return "IORegistryEntryCreateCFProperty() failed"; - if (ffCfDictGetString(properties, CFSTR("product-name"), result)) - break; - } - - IOObjectRelease(registryEntry); - return NULL; + return ffCfStrGetString(productName, result); } const char* ffDetectHost(FFHostResult* host) diff --git a/src/detection/physicaldisk/physicaldisk_apple.c b/src/detection/physicaldisk/physicaldisk_apple.c index 4fbc84951..8f4a11420 100644 --- a/src/detection/physicaldisk/physicaldisk_apple.c +++ b/src/detection/physicaldisk/physicaldisk_apple.c @@ -9,14 +9,6 @@ #include #include -static inline void wrapIoObjectRelease(io_service_t* service) -{ - assert(service); - if (*service) - IOObjectRelease(*service); -} -#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease))) - static inline void wrapIoDestroyPlugInInterface(IOCFPlugInInterface*** pluginInf) { assert(pluginInf); @@ -49,11 +41,11 @@ static const char* detectSsdTemp(io_service_t entryPhysical, double* temp) const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) { FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = 0; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS) + if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS) return "IOServiceGetMatchingServices() failed"; io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryPartition = registryEntry; diff --git a/src/detection/temps/temps_apple.c b/src/detection/temps/temps_apple.c index 2fbc2ae09..c4cef7827 100644 --- a/src/detection/temps/temps_apple.c +++ b/src/detection/temps/temps_apple.c @@ -85,12 +85,9 @@ static void smcUltostr(char *str, uint32_t val) static const char *smcCall(io_connect_t conn, uint32_t selector, SmcKeyData_t *inputStructure, SmcKeyData_t *outputStructure) { - size_t structureInputSize; - size_t structureOutputSize; - structureInputSize = sizeof(SmcKeyData_t); - structureOutputSize = sizeof(SmcKeyData_t); + size_t size = sizeof(SmcKeyData_t); - if (IOConnectCallStructMethod(conn, selector, inputStructure, structureInputSize, outputStructure, &structureOutputSize) != kIOReturnSuccess) + if (IOConnectCallStructMethod(conn, selector, inputStructure, size, outputStructure, &size) != kIOReturnSuccess) return "IOConnectCallStructMethod(conn) failed"; return NULL; } @@ -140,17 +137,13 @@ static const char *smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcV static const char *smcOpen(io_connect_t *conn) { - io_iterator_t iterator; - if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSMC"), &iterator) != kIOReturnSuccess) - return "IOServiceGetMatchingServices() failed"; - - io_object_t device = IOIteratorNext(iterator); - IOObjectRelease(iterator); - if (device == 0) + io_object_t device = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMC")); + if (!device) return "No SMC device found"; kern_return_t result = IOServiceOpen(device, mach_task_self(), 0, conn); IOObjectRelease(device); + if (result != kIOReturnSuccess) return "IOServiceOpen() failed"; @@ -290,10 +283,13 @@ static bool detectTemp(io_connect_t conn, const char *sensor, double* sum) const char *ffDetectSmcTemps(enum FFTempType type, double *result) { static io_connect_t conn; - static dispatch_once_t once_control; - dispatch_once_f(&once_control, &conn, (dispatch_function_t) smcOpen); - if(!conn) - return "smcOpen() failed"; + if (!conn) + { + if (smcOpen(&conn) != NULL) + conn = (io_connect_t) -1; + } + else if (conn == (io_connect_t) -1) + return "Could not open SMC connection"; uint32_t count = 0; *result = 0; diff --git a/src/util/apple/cf_helpers.c b/src/util/apple/cf_helpers.c index 962334ed5..7b501af71 100644 --- a/src/util/apple/cf_helpers.c +++ b/src/util/apple/cf_helpers.c @@ -19,26 +19,42 @@ const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result) return "TypeID is neither 'CFNumber' nor 'CFData'"; } -const char* ffCfStrGetString(CFStringRef str, FFstrbuf* result) +const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) { - if (!str) + if (!cf) { ffStrbufClear(result); return NULL; } - uint32_t length = (uint32_t)CFStringGetLength(str); - //CFString stores UTF16 characters, therefore may require larger buffer to convert to UTF8 string - ffStrbufEnsureFree(result, length * 2); - if(!CFStringGetCString(str, result->chars, result->allocated, kCFStringEncodingUTF8)) + if (CFGetTypeID(cf) == CFStringGetTypeID()) { - ffStrbufEnsureFree(result, length * 4); - if(!CFStringGetCString(str, result->chars, result->allocated, kCFStringEncodingUTF8)) - return "CFStringGetCString() failed"; + CFStringRef cfStr = (CFStringRef)cf; + uint32_t length = (uint32_t)CFStringGetLength(cfStr); + //CFString stores UTF16 characters, therefore may require larger buffer to convert to UTF8 string + ffStrbufEnsureFree(result, length * 2); + if (!CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8)) + { + ffStrbufEnsureFree(result, length * 4); + if(!CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8)) + return "CFStringGetCString() failed"; + } + // CFStringGetCString ensures the buffer is NUL terminated + // https://developer.apple.com/documentation/corefoundation/1542721-cfstringgetcstring + result->length = (uint32_t) strnlen(result->chars, (uint32_t)result->allocated); } - // CFStringGetCString ensures the buffer is NUL terminated - // https://developer.apple.com/documentation/corefoundation/1542721-cfstringgetcstring - result->length = (uint32_t) strnlen(result->chars, (uint32_t)result->allocated); + else if (CFGetTypeID(cf) == CFDataGetTypeID()) + { + CFDataRef cfData = (CFDataRef)cf; + uint32_t length = (uint32_t)CFDataGetLength(cfData); + ffStrbufEnsureFree(result, length + 1); + CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*)result->chars); + result->length = (uint32_t)strnlen(result->chars, length); + result->chars[result->length] = '\0'; + } + else + return "TypeID is neither 'CFString' nor 'CFData'"; + return NULL; } @@ -48,22 +64,7 @@ const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* r if(cf == NULL) return "CFDictionaryGetValue() failed"; - if(CFGetTypeID(cf) == CFStringGetTypeID()) - { - return ffCfStrGetString((CFStringRef)cf, result); - } - else if(CFGetTypeID(cf) == CFDataGetTypeID()) - { - CFDataRef cfData = (CFDataRef)cf; - uint32_t length = (uint32_t)CFDataGetLength(cfData); - ffStrbufEnsureFree(result, length + 1); - CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*)result->chars); - result->length = (uint32_t)strnlen(result->chars, length); - result->chars[result->length] = '\0'; - return NULL; - } - - return "TypeID is neither 'CFString' nor 'CFData'"; + return ffCfStrGetString(cf, result); } const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result) diff --git a/src/util/apple/cf_helpers.h b/src/util/apple/cf_helpers.h index eba56c127..a0e494710 100644 --- a/src/util/apple/cf_helpers.h +++ b/src/util/apple/cf_helpers.h @@ -5,9 +5,10 @@ #include "fastfetch.h" #include +#include //Return error info if failed, NULL otherwise -const char* ffCfStrGetString(CFStringRef str, FFstrbuf* result); +const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result); const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result); const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result); const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result); @@ -29,4 +30,12 @@ static inline void cfReleaseWrapper(void* type) #define FF_CFTYPE_AUTO_RELEASE __attribute__((__cleanup__(cfReleaseWrapper))) +static inline void wrapIoObjectRelease(io_service_t* service) +{ + assert(service); + if (*service) + IOObjectRelease(*service); +} +#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease))) + #endif