X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fe8ab488e9161c46dd9885d58fc52996dc0249ff..0a7de7458d150b5d4dffc935ba399be265ef0a1a:/iokit/Kernel/IOReporter.cpp diff --git a/iokit/Kernel/IOReporter.cpp b/iokit/Kernel/IOReporter.cpp index e132bc17e..7d2bf3268 100644 --- a/iokit/Kernel/IOReporter.cpp +++ b/iokit/Kernel/IOReporter.cpp @@ -1,8 +1,8 @@ /* * Copyright (c) 2012-2013 Apple Computer, Inc. All Rights Reserved. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,7 +22,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ @@ -46,111 +46,111 @@ static const OSSymbol *gIOReportNoChannelName = OSSymbol::withCString("_NO_NAME_ /**************************************/ IOReturn IOReporter::configureAllReports(OSSet *reporters, - IOReportChannelList *channelList, - IOReportConfigureAction action, - void *result, - void *destination) + IOReportChannelList *channelList, + IOReportConfigureAction action, + void *result, + void *destination) { - IOReturn rval = kIOReturnError; - OSCollectionIterator *iterator = NULL; - - if (reporters == NULL || channelList == NULL || result == NULL) { - rval = kIOReturnBadArgument; - goto finish; - } - - switch (action) { - - case kIOReportGetDimensions: - case kIOReportEnable: - case kIOReportDisable: - { - OSObject * object; - iterator = OSCollectionIterator::withCollection(reporters); - - while ((object = iterator->getNextObject())) { - - IOReporter *rep = OSDynamicCast(IOReporter, object); - - if (rep) { - (void)rep->configureReport(channelList, action, result, destination); - } else { - rval = kIOReturnUnsupported; // kIOReturnNotFound? - goto finish; - } - } - - break; - } - - case kIOReportTraceOnChange: - case kIOReportNotifyHubOnChange: - default: - rval = kIOReturnUnsupported; - goto finish; - } - - rval = kIOReturnSuccess; - + IOReturn rval = kIOReturnError; + OSCollectionIterator *iterator = NULL; + + if (reporters == NULL || channelList == NULL || result == NULL) { + rval = kIOReturnBadArgument; + goto finish; + } + + switch (action) { + case kIOReportGetDimensions: + case kIOReportEnable: + case kIOReportDisable: + { + OSObject * object; + iterator = OSCollectionIterator::withCollection(reporters); + + while ((object = iterator->getNextObject())) { + IOReporter *rep = OSDynamicCast(IOReporter, object); + + if (rep) { + (void)rep->configureReport(channelList, action, result, destination); + } else { + rval = kIOReturnUnsupported; // kIOReturnNotFound? + goto finish; + } + } + + break; + } + + case kIOReportTraceOnChange: + case kIOReportNotifyHubOnChange: + default: + rval = kIOReturnUnsupported; + goto finish; + } + + rval = kIOReturnSuccess; + finish: - if (iterator) iterator->release(); + if (iterator) { + iterator->release(); + } - return rval; + return rval; } // the duplication in these functions almost makes one want Objective-C SEL* ;) IOReturn IOReporter::updateAllReports(OSSet *reporters, - IOReportChannelList *channelList, - IOReportConfigureAction action, - void *result, - void *destination) + IOReportChannelList *channelList, + IOReportConfigureAction action, + void *result, + void *destination) { - IOReturn rval = kIOReturnError; - OSCollectionIterator *iterator = NULL; - - if (reporters == NULL || - channelList == NULL || - result == NULL || - destination == NULL) { - rval = kIOReturnBadArgument; - goto finish; - } - - switch (action) { - - case kIOReportCopyChannelData: - { - OSObject * object; - iterator = OSCollectionIterator::withCollection(reporters); - - while ((object = iterator->getNextObject())) { - - IOReporter *rep = OSDynamicCast(IOReporter, object); - - if (rep) { - (void)rep->updateReport(channelList, action, result, destination); - } else { - rval = kIOReturnUnsupported; // kIOReturnNotFound? - goto finish; - } - } - - break; - } - - case kIOReportTraceChannelData: - default: - rval = kIOReturnUnsupported; - goto finish; - } - - rval = kIOReturnSuccess; + IOReturn rval = kIOReturnError; + OSCollectionIterator *iterator = NULL; + + if (reporters == NULL || + channelList == NULL || + result == NULL || + destination == NULL) { + rval = kIOReturnBadArgument; + goto finish; + } + + switch (action) { + case kIOReportCopyChannelData: + { + OSObject * object; + iterator = OSCollectionIterator::withCollection(reporters); + + while ((object = iterator->getNextObject())) { + IOReporter *rep = OSDynamicCast(IOReporter, object); + + if (rep) { + (void)rep->updateReport(channelList, action, result, destination); + } else { + rval = kIOReturnUnsupported; // kIOReturnNotFound? + goto finish; + } + } + + break; + } + + case kIOReportTraceChannelData: + default: + rval = kIOReturnUnsupported; + goto finish; + } + + rval = kIOReturnSuccess; finish: - if (iterator) iterator->release(); + if (iterator) { + iterator->release(); + } - return rval; + return rval; } @@ -160,69 +160,73 @@ finish: bool IOReporter::init(IOService *reportingService, - IOReportChannelType channelType, - IOReportUnits unit) + IOReportChannelType channelType, + IOReportUnit unit) { - bool success = false; - - // ::free() relies on these being initialized - _reporterLock = NULL; - _configLock = NULL; - _elements = NULL; - _enableCounts = NULL; - _channelNames = NULL; - - if (channelType.report_format == kIOReportInvalidFormat) { - IORLOG("init ERROR: Channel Type ill-defined"); - goto finish; - } - - _driver_id = reportingService->getRegistryEntryID(); - if (_driver_id == 0) { - IORLOG("init() ERROR: no registry ID"); - goto finish; - } - - if (!super::init()) return false; - - _channelDimension = channelType.nelements; - _channelType = channelType; - // FIXME: need to look up dynamically - if (unit == kIOReportUnitHWTicks) { -#if defined(__i386__) || defined(__x86_64__) - // Most, but not all Macs use 1GHz - unit = kIOReportUnit1GHzTicks; + bool success = false; + + // ::free() relies on these being initialized + _reporterLock = NULL; + _configLock = NULL; + _elements = NULL; + _enableCounts = NULL; + _channelNames = NULL; + + if (channelType.report_format == kIOReportInvalidFormat) { + IORLOG("init ERROR: Channel Type ill-defined"); + goto finish; + } + + _driver_id = reportingService->getRegistryEntryID(); + if (_driver_id == 0) { + IORLOG("init() ERROR: no registry ID"); + goto finish; + } + + if (!super::init()) { + return false; + } + + _channelDimension = channelType.nelements; + _channelType = channelType; + // FIXME: need to look up dynamically + if (unit == kIOReportUnitHWTicks) { +#if defined(__arm__) || defined(__arm64__) + unit = kIOReportUnit24MHzTicks; +#elif defined(__i386__) || defined(__x86_64__) + // Most, but not all Macs use 1GHz + unit = kIOReportUnit1GHzTicks; #else #error kIOReportUnitHWTicks not defined #endif - } - _unit = unit; - - // Allocate a reporter (data) lock - _reporterLock = IOSimpleLockAlloc(); - if (!_reporterLock) goto finish; - _reporterIsLocked = false; - - // Allocate a config lock - _configLock = IOLockAlloc(); - if (!_configLock) goto finish; - _reporterConfigIsLocked = false; - - // Allocate channel names array - _channelNames = OSArray::withCapacity(1); - if (!_channelNames) goto finish; - - // success - success = true; + } + _unit = unit; + + // Allocate a reporter (data) lock + _reporterLock = IOSimpleLockAlloc(); + if (!_reporterLock) { + goto finish; + } + _reporterIsLocked = false; + + // Allocate a config lock + _configLock = IOLockAlloc(); + if (!_configLock) { + goto finish; + } + _reporterConfigIsLocked = false; + + // Allocate channel names array + _channelNames = OSArray::withCapacity(1); + if (!_channelNames) { + goto finish; + } + + // success + success = true; finish: - if (!success) { - if (_configLock) IOLockFree(_configLock); - if (_reporterLock) IOSimpleLockFree(_reporterLock); - if (_channelNames) _channelNames->release(); - } - - return success; + return success; } @@ -234,148 +238,154 @@ finish: // to ensure that _ = NULL void IOReporter::free(void) -{ - if (_configLock) IOLockFree(_configLock); - if (_reporterLock) IOSimpleLockFree(_reporterLock); - - if (_elements) { - PREFL_MEMOP_PANIC(_nElements, IOReportElement); - IOFree(_elements, (size_t)_nElements * sizeof(IOReportElement)); - } - if (_enableCounts) { - PREFL_MEMOP_PANIC(_nChannels, int); - IOFree(_enableCounts, (size_t)_nChannels * sizeof(int)); - } - - super::free(); +{ + OSSafeReleaseNULL(_channelNames); + + if (_configLock) { + IOLockFree(_configLock); + } + if (_reporterLock) { + IOSimpleLockFree(_reporterLock); + } + + if (_elements) { + PREFL_MEMOP_PANIC(_nElements, IOReportElement); + IOFree(_elements, (size_t)_nElements * sizeof(IOReportElement)); + } + if (_enableCounts) { + PREFL_MEMOP_PANIC(_nChannels, int); + IOFree(_enableCounts, (size_t)_nChannels * sizeof(int)); + } + + super::free(); } /* -#define TESTALLOC() do { \ - void *tbuf; \ - tbuf = IOMalloc(10); \ - IOFree(tbuf, 10); \ - IORLOG("%s:%d - _reporterIsLocked = %d & allocation successful", \ - __PRETTY_FUNCTION__, __LINE__, _reporterIsLocked); \ -} while (0); -*/ + #define TESTALLOC() do { \ + * void *tbuf; \ + * tbuf = IOMalloc(10); \ + * IOFree(tbuf, 10); \ + * IORLOG("%s:%d - _reporterIsLocked = %d & allocation successful", \ + * __PRETTY_FUNCTION__, __LINE__, _reporterIsLocked); \ + * } while (0); + */ IOReturn IOReporter::addChannel(uint64_t channelID, - const char *channelName /* = NULL */) + const char *channelName /* = NULL */) { - IOReturn res = kIOReturnError, kerr; - const OSSymbol *symChannelName = NULL; - int oldNChannels, newNChannels = 0, freeNChannels = 0; - - IORLOG("IOReporter::addChannel %llx", channelID); - - // protect instance variables (but not contents) - lockReporterConfig(); - - // FIXME: Check if any channel is already present and return error - - // addChannel() always adds one channel - oldNChannels = _nChannels; - if (oldNChannels < 0 || oldNChannels > INT_MAX - 1) { - res = kIOReturnOverrun; - goto finish; - } - newNChannels = oldNChannels + 1; - freeNChannels = newNChannels; // until swap success - - // Expand addChannel()-specific data structure - if (_channelNames->ensureCapacity((unsigned)newNChannels) < - (unsigned)newNChannels) { - res = kIOReturnNoMemory; goto finish; - } - if (channelName) { - symChannelName = OSSymbol::withCString(channelName); - if (!symChannelName) { - res = kIOReturnNoMemory; goto finish; - } - } else { - // grab a reference to our shared global - symChannelName = gIOReportNoChannelName; - symChannelName->retain(); - } - - // allocate new buffers into _swap* variables - if ((kerr = handleSwapPrepare(newNChannels))) { - // on error, channels are *not* swapped - res = kerr; goto finish; - } - - // exchange main and _swap* buffers with buffer contents protected - // IOReporter::handleAddChannelSwap() also increments _nElements, etc - lockReporter(); - res = handleAddChannelSwap(channelID, symChannelName); - unlockReporter(); - // On failure, handleAddChannelSwap() leaves *new* buffers in _swap*. - // On success, it's the old buffers, so we put the right size in here. - if (res == kIOReturnSuccess) { - freeNChannels = oldNChannels; - } + IOReturn res = kIOReturnError, kerr; + const OSSymbol *symChannelName = NULL; + int oldNChannels, newNChannels = 0, freeNChannels = 0; + + IORLOG("IOReporter::addChannel %llx", channelID); + + // protect instance variables (but not contents) + lockReporterConfig(); + + // FIXME: Check if any channel is already present and return error + + // addChannel() always adds one channel + oldNChannels = _nChannels; + if (oldNChannels < 0 || oldNChannels > INT_MAX - 1) { + res = kIOReturnOverrun; + goto finish; + } + newNChannels = oldNChannels + 1; + freeNChannels = newNChannels; // until swap success + + // Expand addChannel()-specific data structure + if (_channelNames->ensureCapacity((unsigned)newNChannels) < + (unsigned)newNChannels) { + res = kIOReturnNoMemory; goto finish; + } + if (channelName) { + symChannelName = OSSymbol::withCString(channelName); + if (!symChannelName) { + res = kIOReturnNoMemory; goto finish; + } + } else { + // grab a reference to our shared global + symChannelName = gIOReportNoChannelName; + symChannelName->retain(); + } + + // allocate new buffers into _swap* variables + if ((kerr = handleSwapPrepare(newNChannels))) { + // on error, channels are *not* swapped + res = kerr; goto finish; + } + + // exchange main and _swap* buffers with buffer contents protected + // IOReporter::handleAddChannelSwap() also increments _nElements, etc + lockReporter(); + res = handleAddChannelSwap(channelID, symChannelName); + unlockReporter(); + // On failure, handleAddChannelSwap() leaves *new* buffers in _swap*. + // On success, it's the old buffers, so we put the right size in here. + if (res == kIOReturnSuccess) { + freeNChannels = oldNChannels; + } finish: - // free up not-in-use buffers (tracked by _swap*) - handleSwapCleanup(freeNChannels); - if (symChannelName) symChannelName->release(); - unlockReporterConfig(); - - return res; + // free up not-in-use buffers (tracked by _swap*) + handleSwapCleanup(freeNChannels); + if (symChannelName) { + symChannelName->release(); + } + unlockReporterConfig(); + + return res; } IOReportLegendEntry* IOReporter::createLegend(void) { - IOReportLegendEntry *legendEntry = NULL; - - lockReporterConfig(); - - legendEntry = handleCreateLegend(); - - unlockReporterConfig(); - - return legendEntry; + IOReportLegendEntry *legendEntry = NULL; + + lockReporterConfig(); + + legendEntry = handleCreateLegend(); + + unlockReporterConfig(); + + return legendEntry; } IOReturn IOReporter::configureReport(IOReportChannelList *channelList, - IOReportConfigureAction action, - void *result, - void *destination) + IOReportConfigureAction action, + void *result, + void *destination) { - IOReturn res = kIOReturnError; - - lockReporterConfig(); - - res = handleConfigureReport(channelList, action, result, destination); - - unlockReporterConfig(); - - return res; - + IOReturn res = kIOReturnError; + + lockReporterConfig(); + + res = handleConfigureReport(channelList, action, result, destination); + + unlockReporterConfig(); + + return res; } IOReturn IOReporter::updateReport(IOReportChannelList *channelList, - IOReportConfigureAction action, - void *result, - void *destination) + IOReportConfigureAction action, + void *result, + void *destination) { - IOReturn res = kIOReturnError; - - lockReporter(); - - res = handleUpdateReport(channelList, action, result, destination); - - unlockReporter(); - - return res; - + IOReturn res = kIOReturnError; + + lockReporter(); + + res = handleUpdateReport(channelList, action, result, destination); + + unlockReporter(); + + return res; } @@ -387,210 +397,209 @@ IOReporter::updateReport(IOReportChannelList *channelList, void IOReporter::lockReporter() { - _interruptState = IOSimpleLockLockDisableInterrupt(_reporterLock); - _reporterIsLocked = true; + _interruptState = IOSimpleLockLockDisableInterrupt(_reporterLock); + _reporterIsLocked = true; } void IOReporter::unlockReporter() { - _reporterIsLocked = false; - IOSimpleLockUnlockEnableInterrupt(_reporterLock, _interruptState); + _reporterIsLocked = false; + IOSimpleLockUnlockEnableInterrupt(_reporterLock, _interruptState); } void IOReporter::lockReporterConfig() { - IOLockLock(_configLock); - _reporterConfigIsLocked = true; + IOLockLock(_configLock); + _reporterConfigIsLocked = true; } void IOReporter::unlockReporterConfig() { - _reporterConfigIsLocked = false; - IOLockUnlock(_configLock); + _reporterConfigIsLocked = false; + IOLockUnlock(_configLock); } IOReturn IOReporter::handleSwapPrepare(int newNChannels) { - IOReturn res = kIOReturnError; - int newNElements; - size_t newElementsSize, newECSize; - - // analyzer appeasement - newElementsSize = newECSize = 0; - - //IORLOG("IOReporter::handleSwapPrepare"); - - IOREPORTER_CHECK_CONFIG_LOCK(); - - if (newNChannels < _nChannels) { - panic("%s doesn't support shrinking", __func__); - } - if (newNChannels <= 0 || _channelDimension <= 0) { - res = kIOReturnUnderrun; - goto finish; - } - if (_swapElements || _swapEnableCounts) { - panic("IOReporter::_swap* already in use"); - } - - // calculate the number of elements given #ch & the dimension of each - if (newNChannels < 0 || newNChannels > INT_MAX / _channelDimension) { - res = kIOReturnOverrun; - goto finish; - } - newNElements = newNChannels * _channelDimension; - - // Allocate memory for the new array of report elements - PREFL_MEMOP_FAIL(newNElements, IOReportElement); - newElementsSize = (size_t)newNElements * sizeof(IOReportElement); - _swapElements = (IOReportElement *)IOMalloc(newElementsSize); - if (_swapElements == NULL) { - res = kIOReturnNoMemory; goto finish; - } - memset(_swapElements, 0, newElementsSize); - - // Allocate memory for the new array of channel watch counts - PREFL_MEMOP_FAIL(newNChannels, int); - newECSize = (size_t)newNChannels * sizeof(int); - _swapEnableCounts = (int *)IOMalloc(newECSize); - if (_swapEnableCounts == NULL){ - res = kIOReturnNoMemory; goto finish; - } - memset(_swapEnableCounts, 0, newECSize); - - // success - res = kIOReturnSuccess; + IOReturn res = kIOReturnError; + int newNElements; + size_t newElementsSize, newECSize; + + // analyzer appeasement + newElementsSize = newECSize = 0; + + //IORLOG("IOReporter::handleSwapPrepare"); + + IOREPORTER_CHECK_CONFIG_LOCK(); + + if (newNChannels < _nChannels) { + panic("%s doesn't support shrinking", __func__); + } + if (newNChannels <= 0 || _channelDimension <= 0) { + res = kIOReturnUnderrun; + goto finish; + } + if (_swapElements || _swapEnableCounts) { + panic("IOReporter::_swap* already in use"); + } + + // calculate the number of elements given #ch & the dimension of each + if (newNChannels < 0 || newNChannels > INT_MAX / _channelDimension) { + res = kIOReturnOverrun; + goto finish; + } + newNElements = newNChannels * _channelDimension; + + // Allocate memory for the new array of report elements + PREFL_MEMOP_FAIL(newNElements, IOReportElement); + newElementsSize = (size_t)newNElements * sizeof(IOReportElement); + _swapElements = (IOReportElement *)IOMalloc(newElementsSize); + if (_swapElements == NULL) { + res = kIOReturnNoMemory; goto finish; + } + memset(_swapElements, 0, newElementsSize); + + // Allocate memory for the new array of channel watch counts + PREFL_MEMOP_FAIL(newNChannels, int); + newECSize = (size_t)newNChannels * sizeof(int); + _swapEnableCounts = (int *)IOMalloc(newECSize); + if (_swapEnableCounts == NULL) { + res = kIOReturnNoMemory; goto finish; + } + memset(_swapEnableCounts, 0, newECSize); + + // success + res = kIOReturnSuccess; finish: - if (res) { - if (_swapElements) { - IOFree(_swapElements, newElementsSize); - _swapElements = NULL; - } - if (_swapEnableCounts) { - IOFree(_swapEnableCounts, newECSize); - _swapEnableCounts = NULL; - } - } - - return res; + if (res) { + if (_swapElements) { + IOFree(_swapElements, newElementsSize); + _swapElements = NULL; + } + if (_swapEnableCounts) { + IOFree(_swapEnableCounts, newECSize); + _swapEnableCounts = NULL; + } + } + + return res; } IOReturn IOReporter::handleAddChannelSwap(uint64_t channel_id, - const OSSymbol *symChannelName) + const OSSymbol *symChannelName) { - IOReturn res = kIOReturnError; - int cnt; - int *tmpWatchCounts = NULL; - IOReportElement *tmpElements = NULL; - bool swapComplete = false; - - //IORLOG("IOReporter::handleSwap"); - - IOREPORTER_CHECK_CONFIG_LOCK(); - IOREPORTER_CHECK_LOCK(); - - if (!_swapElements || !_swapEnableCounts) { - IORLOG("IOReporter::handleSwap ERROR swap variables uninitialized!"); - goto finish; - } - - // Copy any existing elements to the new location - //IORLOG("handleSwap (base) -> copying %u elements over...", _nChannels); - if (_elements) { - PREFL_MEMOP_PANIC(_nElements, IOReportElement); - memcpy(_swapElements, _elements, - (size_t)_nElements * sizeof(IOReportElement)); - - PREFL_MEMOP_PANIC(_nElements, int); - memcpy(_swapEnableCounts, _enableCounts, - (size_t)_nChannels * sizeof(int)); - } - - // Update principal instance variables, keep old buffers for cleanup - tmpElements = _elements; - _elements = _swapElements; - _swapElements = tmpElements; - - tmpWatchCounts = _enableCounts; - _enableCounts = _swapEnableCounts; - _swapEnableCounts = tmpWatchCounts; - - swapComplete = true; - - // but _nChannels & _nElements is still the old (one smaller) size - - // Initialize new element metadata (existing elements copied above) - for (cnt = 0; cnt < _channelDimension; cnt++) { - - _elements[_nElements + cnt].channel_id = channel_id; - _elements[_nElements + cnt].provider_id = _driver_id; - _elements[_nElements + cnt].channel_type = _channelType; - _elements[_nElements + cnt].channel_type.element_idx = cnt; - - //IOREPORTER_DEBUG_ELEMENT(_swapNElements + cnt); - } - - // Store a channel name at the end - if (!_channelNames->setObject((unsigned)_nChannels, symChannelName)) { - // Should never happen because we ensured capacity in addChannel() - res = kIOReturnNoMemory; - goto finish; - } - - // And update the metadata: addChannel() always adds just one channel - _nChannels += 1; - _nElements += _channelDimension; - - // success - res = kIOReturnSuccess; + IOReturn res = kIOReturnError; + int cnt; + int *tmpWatchCounts = NULL; + IOReportElement *tmpElements = NULL; + bool swapComplete = false; + + //IORLOG("IOReporter::handleSwap"); + + IOREPORTER_CHECK_CONFIG_LOCK(); + IOREPORTER_CHECK_LOCK(); + + if (!_swapElements || !_swapEnableCounts) { + IORLOG("IOReporter::handleSwap ERROR swap variables uninitialized!"); + goto finish; + } + + // Copy any existing elements to the new location + //IORLOG("handleSwap (base) -> copying %u elements over...", _nChannels); + if (_elements) { + PREFL_MEMOP_PANIC(_nElements, IOReportElement); + memcpy(_swapElements, _elements, + (size_t)_nElements * sizeof(IOReportElement)); + + PREFL_MEMOP_PANIC(_nElements, int); + memcpy(_swapEnableCounts, _enableCounts, + (size_t)_nChannels * sizeof(int)); + } + + // Update principal instance variables, keep old buffers for cleanup + tmpElements = _elements; + _elements = _swapElements; + _swapElements = tmpElements; + + tmpWatchCounts = _enableCounts; + _enableCounts = _swapEnableCounts; + _swapEnableCounts = tmpWatchCounts; + + swapComplete = true; + + // but _nChannels & _nElements is still the old (one smaller) size + + // Initialize new element metadata (existing elements copied above) + for (cnt = 0; cnt < _channelDimension; cnt++) { + _elements[_nElements + cnt].channel_id = channel_id; + _elements[_nElements + cnt].provider_id = _driver_id; + _elements[_nElements + cnt].channel_type = _channelType; + _elements[_nElements + cnt].channel_type.element_idx = cnt; + + //IOREPORTER_DEBUG_ELEMENT(_swapNElements + cnt); + } + + // Store a channel name at the end + if (!_channelNames->setObject((unsigned)_nChannels, symChannelName)) { + // Should never happen because we ensured capacity in addChannel() + res = kIOReturnNoMemory; + goto finish; + } + + // And update the metadata: addChannel() always adds just one channel + _nChannels += 1; + _nElements += _channelDimension; + + // success + res = kIOReturnSuccess; finish: - if (res && swapComplete) { - // unswap so new buffers get cleaned up instead of old - tmpElements = _elements; - _elements = _swapElements; - _swapElements = tmpElements; - - tmpWatchCounts = _enableCounts; - _enableCounts = _swapEnableCounts; - _swapEnableCounts = tmpWatchCounts; - } - return res; + if (res && swapComplete) { + // unswap so new buffers get cleaned up instead of old + tmpElements = _elements; + _elements = _swapElements; + _swapElements = tmpElements; + + tmpWatchCounts = _enableCounts; + _enableCounts = _swapEnableCounts; + _swapEnableCounts = tmpWatchCounts; + } + return res; } void IOReporter::handleSwapCleanup(int swapNChannels) { - int swapNElements; - - if (!_channelDimension || swapNChannels > INT_MAX / _channelDimension) { - panic("%s - can't free %d channels of dimension %d", __func__, - swapNChannels, _channelDimension); - } - swapNElements = swapNChannels * _channelDimension; - - IOREPORTER_CHECK_CONFIG_LOCK(); - - // release buffers no longer used after swapping - if (_swapElements) { - PREFL_MEMOP_PANIC(swapNElements, IOReportElement); - IOFree(_swapElements, (size_t)swapNElements * sizeof(IOReportElement)); - _swapElements = NULL; - } - if (_swapEnableCounts) { - PREFL_MEMOP_PANIC(swapNChannels, int); - IOFree(_swapEnableCounts, (size_t)swapNChannels * sizeof(int)); - _swapEnableCounts = NULL; - } + int swapNElements; + + if (!_channelDimension || swapNChannels > INT_MAX / _channelDimension) { + panic("%s - can't free %d channels of dimension %d", __func__, + swapNChannels, _channelDimension); + } + swapNElements = swapNChannels * _channelDimension; + + IOREPORTER_CHECK_CONFIG_LOCK(); + + // release buffers no longer used after swapping + if (_swapElements) { + PREFL_MEMOP_PANIC(swapNElements, IOReportElement); + IOFree(_swapElements, (size_t)swapNElements * sizeof(IOReportElement)); + _swapElements = NULL; + } + if (_swapEnableCounts) { + PREFL_MEMOP_PANIC(swapNChannels, int); + IOFree(_swapEnableCounts, (size_t)swapNChannels * sizeof(int)); + _swapEnableCounts = NULL; + } } @@ -599,353 +608,360 @@ IOReporter::handleSwapCleanup(int swapNChannels) // clients can use to cull unused reporters after configureReport(disable). IOReturn IOReporter::handleConfigureReport(IOReportChannelList *channelList, - IOReportConfigureAction action, - void *result, - void *destination) + IOReportConfigureAction action, + void *result, + void *destination) { - IOReturn res = kIOReturnError; - int channel_index = 0; - uint32_t chIdx; - int *nElements, *nChannels; - - // Check on channelList and result because used below - if (!channelList || !result) goto finish; - - //IORLOG("IOReporter::configureReport action %u for %u channels", - // action, channelList->nchannels); - - // Make sure channel is present, increase matching watch count, 'result' - for (chIdx = 0; chIdx < channelList->nchannels; chIdx++) { - - if (getChannelIndex(channelList->channels[chIdx].channel_id, - &channel_index) == kIOReturnSuccess) { - // IORLOG("reporter %p recognizes channel %lld", this, channelList->channels[chIdx].channel_id); - - switch (action) { - - case kIOReportEnable: - nChannels = (int*)result; - _enabled++; - _enableCounts[channel_index]++; - (*nChannels)++; - break; - - case kIOReportDisable: - nChannels = (int*)result; - _enabled--; - _enableCounts[channel_index]--; - (*nChannels)++; - break; - - case kIOReportGetDimensions: - nElements = (int *)result; - *nElements += _channelDimension; - break; - - default: - IORLOG("ERROR configureReport unknown action!"); - break; - } - } - } - - // success - res = kIOReturnSuccess; - + IOReturn res = kIOReturnError; + int channel_index = 0; + uint32_t chIdx; + int *nElements, *nChannels; + + // Check on channelList and result because used below + if (!channelList || !result) { + goto finish; + } + + //IORLOG("IOReporter::configureReport action %u for %u channels", + // action, channelList->nchannels); + + // Make sure channel is present, increase matching watch count, 'result' + for (chIdx = 0; chIdx < channelList->nchannels; chIdx++) { + if (getChannelIndex(channelList->channels[chIdx].channel_id, + &channel_index) == kIOReturnSuccess) { + // IORLOG("reporter %p recognizes channel %lld", this, channelList->channels[chIdx].channel_id); + + switch (action) { + case kIOReportEnable: + nChannels = (int*)result; + _enabled++; + _enableCounts[channel_index]++; + (*nChannels)++; + break; + + case kIOReportDisable: + nChannels = (int*)result; + _enabled--; + _enableCounts[channel_index]--; + (*nChannels)++; + break; + + case kIOReportGetDimensions: + nElements = (int *)result; + *nElements += _channelDimension; + break; + + default: + IORLOG("ERROR configureReport unknown action!"); + break; + } + } + } + + // success + res = kIOReturnSuccess; + finish: - return res; + return res; } IOReturn IOReporter::handleUpdateReport(IOReportChannelList *channelList, - IOReportConfigureAction action, - void *result, - void *destination) + IOReportConfigureAction action, + void *result, + void *destination) { - IOReturn res = kIOReturnError; - int *nElements = (int *)result; - int channel_index = 0; - uint32_t chIdx; - IOBufferMemoryDescriptor *dest; - - if (!channelList || !result || !destination) goto finish; - - dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination); - if (dest == NULL) { - // Invalid destination - res = kIOReturnBadArgument; - goto finish; - } - - if (!_enabled) { - goto finish; - } - - for (chIdx = 0; chIdx < channelList->nchannels; chIdx++) { - - if (getChannelIndex(channelList->channels[chIdx].channel_id, - &channel_index) == kIOReturnSuccess) { - - //IORLOG("%s - found channel_id %llx @ index %d", __func__, - // channelList->channels[chIdx].channel_id, - // channel_index); - - switch(action) { - - case kIOReportCopyChannelData: - res = updateChannelValues(channel_index); - if (res) { - IORLOG("ERROR: updateChannelValues() failed: %x", res); - goto finish; - } - - res = updateReportChannel(channel_index, nElements, dest); - if (res) { - IORLOG("ERROR: updateReportChannel() failed: %x", res); - goto finish; - } - break; - - default: - IORLOG("ERROR updateReport unknown action!"); - res = kIOReturnError; - goto finish; - } - } - } - - // success - res = kIOReturnSuccess; - + IOReturn res = kIOReturnError; + int *nElements = (int *)result; + int channel_index = 0; + uint32_t chIdx; + IOBufferMemoryDescriptor *dest; + + if (!channelList || !result || !destination) { + goto finish; + } + + dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination); + if (dest == NULL) { + // Invalid destination + res = kIOReturnBadArgument; + goto finish; + } + + if (!_enabled) { + goto finish; + } + + for (chIdx = 0; chIdx < channelList->nchannels; chIdx++) { + if (getChannelIndex(channelList->channels[chIdx].channel_id, + &channel_index) == kIOReturnSuccess) { + //IORLOG("%s - found channel_id %llx @ index %d", __func__, + // channelList->channels[chIdx].channel_id, + // channel_index); + + switch (action) { + case kIOReportCopyChannelData: + res = updateChannelValues(channel_index); + if (res) { + IORLOG("ERROR: updateChannelValues() failed: %x", res); + goto finish; + } + + res = updateReportChannel(channel_index, nElements, dest); + if (res) { + IORLOG("ERROR: updateReportChannel() failed: %x", res); + goto finish; + } + break; + + default: + IORLOG("ERROR updateReport unknown action!"); + res = kIOReturnError; + goto finish; + } + } + } + + // success + res = kIOReturnSuccess; + finish: - return res; + return res; } IOReportLegendEntry* IOReporter::handleCreateLegend(void) { - IOReportLegendEntry *legendEntry = NULL; - OSArray *channelIDs; - - channelIDs = copyChannelIDs(); - - if (channelIDs) { - legendEntry = IOReporter::legendWith(channelIDs, _channelNames, _channelType, _unit); - channelIDs->release(); - } - - return legendEntry; + IOReportLegendEntry *legendEntry = NULL; + OSArray *channelIDs; + + channelIDs = copyChannelIDs(); + + if (channelIDs) { + legendEntry = IOReporter::legendWith(channelIDs, _channelNames, _channelType, _unit); + channelIDs->release(); + } + + return legendEntry; } IOReturn IOReporter::setElementValues(int element_index, - IOReportElementValues *values, - uint64_t record_time /* = 0 */) + IOReportElementValues *values, + uint64_t record_time /* = 0 */) { - IOReturn res = kIOReturnError; - - IOREPORTER_CHECK_LOCK(); - - if (record_time == 0) { - record_time = mach_absolute_time(); - } - - if (element_index >= _nElements || values == NULL) { - res = kIOReturnBadArgument; - goto finish; - } - - memcpy(&_elements[element_index].values, values, sizeof(IOReportElementValues)); - - _elements[element_index].timestamp = record_time; - - //IOREPORTER_DEBUG_ELEMENT(index); - - res = kIOReturnSuccess; - + IOReturn res = kIOReturnError; + + IOREPORTER_CHECK_LOCK(); + + if (record_time == 0) { + record_time = mach_absolute_time(); + } + + if (element_index >= _nElements || values == NULL) { + res = kIOReturnBadArgument; + goto finish; + } + + memcpy(&_elements[element_index].values, values, sizeof(IOReportElementValues)); + + _elements[element_index].timestamp = record_time; + + //IOREPORTER_DEBUG_ELEMENT(index); + + res = kIOReturnSuccess; + finish: - return res; + return res; } const IOReportElementValues* IOReporter::getElementValues(int element_index) { - IOReportElementValues *elementValues = NULL; - - IOREPORTER_CHECK_LOCK(); - - if (element_index < 0 || element_index >= _nElements) { - IORLOG("ERROR getElementValues out of bounds!"); - goto finish; - } - - elementValues = &_elements[element_index].values; - + IOReportElementValues *elementValues = NULL; + + IOREPORTER_CHECK_LOCK(); + + if (element_index < 0 || element_index >= _nElements) { + IORLOG("ERROR getElementValues out of bounds!"); + goto finish; + } + + elementValues = &_elements[element_index].values; + finish: - return elementValues; + return elementValues; } IOReturn IOReporter::updateChannelValues(int channel_index) { - return kIOReturnSuccess; + return kIOReturnSuccess; } IOReturn IOReporter::updateReportChannel(int channel_index, - int *nElements, - IOBufferMemoryDescriptor *destination) + int *nElements, + IOBufferMemoryDescriptor *destination) { - IOReturn res = kIOReturnError; - int start_element_idx, chElems; - size_t size2cpy; - - res = kIOReturnBadArgument; - if (!nElements || !destination) { - goto finish; - } - if (channel_index > _nChannels) { - goto finish; - } - - IOREPORTER_CHECK_LOCK(); - - res = kIOReturnOverrun; - - start_element_idx = channel_index * _channelDimension; - if (start_element_idx >= _nElements) goto finish; - - chElems = _elements[start_element_idx].channel_type.nelements; - - // make sure we don't go beyond the end of _elements[_nElements-1] - if (start_element_idx + chElems > _nElements) { - goto finish; - } - - PREFL_MEMOP_FAIL(chElems, IOReportElement); - size2cpy = (size_t)chElems * sizeof(IOReportElement); - - // make sure there's space in the destination - if (size2cpy > (destination->getCapacity() - destination->getLength())) { - IORLOG("CRITICAL ERROR: Report Buffer Overflow (buffer cap %luB, length %luB, size2cpy %luB", - (unsigned long)destination->getCapacity(), - (unsigned long)destination->getLength(), - (unsigned long)size2cpy); - goto finish; - } - - destination->appendBytes(&_elements[start_element_idx], size2cpy); - *nElements += chElems; - - res = kIOReturnSuccess; - + IOReturn res = kIOReturnError; + int start_element_idx, chElems; + size_t size2cpy; + + res = kIOReturnBadArgument; + if (!nElements || !destination) { + goto finish; + } + if (channel_index > _nChannels) { + goto finish; + } + + IOREPORTER_CHECK_LOCK(); + + res = kIOReturnOverrun; + + start_element_idx = channel_index * _channelDimension; + if (start_element_idx >= _nElements) { + goto finish; + } + + chElems = _elements[start_element_idx].channel_type.nelements; + + // make sure we don't go beyond the end of _elements[_nElements-1] + if (start_element_idx + chElems > _nElements) { + goto finish; + } + + PREFL_MEMOP_FAIL(chElems, IOReportElement); + size2cpy = (size_t)chElems * sizeof(IOReportElement); + + // make sure there's space in the destination + if (size2cpy > (destination->getCapacity() - destination->getLength())) { + IORLOG("CRITICAL ERROR: Report Buffer Overflow (buffer cap %luB, length %luB, size2cpy %luB", + (unsigned long)destination->getCapacity(), + (unsigned long)destination->getLength(), + (unsigned long)size2cpy); + goto finish; + } + + destination->appendBytes(&_elements[start_element_idx], size2cpy); + *nElements += chElems; + + res = kIOReturnSuccess; + finish: - return res; + return res; } IOReturn IOReporter::copyElementValues(int element_index, - IOReportElementValues *elementValues) + IOReportElementValues *elementValues) { - IOReturn res = kIOReturnError; - - if (!elementValues) goto finish; - - IOREPORTER_CHECK_LOCK(); - - if (element_index >= _nElements) { - IORLOG("ERROR getElementValues out of bounds!"); - res = kIOReturnBadArgument; - goto finish; - } - - memcpy(elementValues, &_elements[element_index].values, sizeof(IOReportElementValues)); - res = kIOReturnSuccess; + IOReturn res = kIOReturnError; + + if (!elementValues) { + goto finish; + } + + IOREPORTER_CHECK_LOCK(); + + if (element_index >= _nElements) { + IORLOG("ERROR getElementValues out of bounds!"); + res = kIOReturnBadArgument; + goto finish; + } + + memcpy(elementValues, &_elements[element_index].values, sizeof(IOReportElementValues)); + res = kIOReturnSuccess; finish: - return res; + return res; } IOReturn IOReporter::getFirstElementIndex(uint64_t channel_id, - int *index) + int *index) { - IOReturn res = kIOReturnError; - int channel_index = 0, element_index = 0; - - if (!index) goto finish; - - res = getChannelIndices(channel_id, &channel_index, &element_index); - - if (res == kIOReturnSuccess) { - *index = element_index; - } + IOReturn res = kIOReturnError; + int channel_index = 0, element_index = 0; + + if (!index) { + goto finish; + } + + res = getChannelIndices(channel_id, &channel_index, &element_index); + + if (res == kIOReturnSuccess) { + *index = element_index; + } finish: - return res; + return res; } IOReturn IOReporter::getChannelIndex(uint64_t channel_id, - int *index) + int *index) { - IOReturn res = kIOReturnError; - int channel_index = 0, element_index = 0; - - if (!index) goto finish; - - res = getChannelIndices(channel_id, &channel_index, &element_index); - - if (res == kIOReturnSuccess) { - *index = channel_index; - } + IOReturn res = kIOReturnError; + int channel_index = 0, element_index = 0; + + if (!index) { + goto finish; + } + + res = getChannelIndices(channel_id, &channel_index, &element_index); + + if (res == kIOReturnSuccess) { + *index = channel_index; + } finish: - return res; + return res; } IOReturn IOReporter::getChannelIndices(uint64_t channel_id, - int *channel_index, - int *element_index) + int *channel_index, + int *element_index) { - IOReturn res = kIOReturnNotFound; - int chIdx, elemIdx; - - if (!channel_index || !element_index) goto finish; - - for (chIdx = 0; chIdx < _nChannels; chIdx++) { - - elemIdx = chIdx * _channelDimension; - if (elemIdx >= _nElements) { - IORLOG("ERROR getChannelIndices out of bounds!"); - res = kIOReturnOverrun; - goto finish; - } - - if (channel_id == _elements[elemIdx].channel_id) { - - // The channel index does not care about the depth of elements... - *channel_index = chIdx; - *element_index = elemIdx; - - res = kIOReturnSuccess; - goto finish; - } - } + IOReturn res = kIOReturnNotFound; + int chIdx, elemIdx; + + if (!channel_index || !element_index) { + goto finish; + } + + for (chIdx = 0; chIdx < _nChannels; chIdx++) { + elemIdx = chIdx * _channelDimension; + if (elemIdx >= _nElements) { + IORLOG("ERROR getChannelIndices out of bounds!"); + res = kIOReturnOverrun; + goto finish; + } + + if (channel_id == _elements[elemIdx].channel_id) { + // The channel index does not care about the depth of elements... + *channel_index = chIdx; + *element_index = elemIdx; + + res = kIOReturnSuccess; + goto finish; + } + } finish: - return res; + return res; } /********************************/ @@ -957,114 +973,121 @@ finish: OSArray* IOReporter::copyChannelIDs() { - int cnt, cnt2; - OSArray *channelIDs = NULL; - OSNumber *tmpNum; - - channelIDs = OSArray::withCapacity((unsigned)_nChannels); - - if (!channelIDs) goto finish; - - for (cnt = 0; cnt < _nChannels; cnt++) { - - cnt2 = cnt * _channelDimension; - - // Encapsulate the Channel ID in OSNumber - tmpNum = OSNumber::withNumber(_elements[cnt2].channel_id, 64); - if (!tmpNum) { - IORLOG("ERROR: Could not create array of channelIDs"); - channelIDs->release(); - channelIDs = NULL; - goto finish; - } - - channelIDs->setObject((unsigned)cnt, tmpNum); - tmpNum->release(); - } + int cnt, cnt2; + OSArray *channelIDs = NULL; + OSNumber *tmpNum; + + channelIDs = OSArray::withCapacity((unsigned)_nChannels); + + if (!channelIDs) { + goto finish; + } + + for (cnt = 0; cnt < _nChannels; cnt++) { + cnt2 = cnt * _channelDimension; + + // Encapsulate the Channel ID in OSNumber + tmpNum = OSNumber::withNumber(_elements[cnt2].channel_id, 64); + if (!tmpNum) { + IORLOG("ERROR: Could not create array of channelIDs"); + channelIDs->release(); + channelIDs = NULL; + goto finish; + } + + channelIDs->setObject((unsigned)cnt, tmpNum); + tmpNum->release(); + } finish: - return channelIDs; + return channelIDs; } // DO NOT REMOVE THIS METHOD WHICH IS THE MAIN LEGEND CREATION FUNCTION /*static */ IOReportLegendEntry* IOReporter::legendWith(OSArray *channelIDs, - OSArray *channelNames, - IOReportChannelType channelType, - IOReportUnits unit) + OSArray *channelNames, + IOReportChannelType channelType, + IOReportUnit unit) { - unsigned int cnt, chCnt; - uint64_t type64; - OSNumber *tmpNum; - const OSSymbol *tmpSymbol; - OSArray *channelLegendArray = NULL, *tmpChannelArray = NULL; - OSDictionary *channelInfoDict = NULL; - IOReportLegendEntry *legendEntry = NULL; - - // No need to check validity of channelNames because param is optional - if (!channelIDs) goto finish; - chCnt = channelIDs->getCount(); - - channelLegendArray = OSArray::withCapacity(chCnt); - - for (cnt = 0; cnt < chCnt; cnt++) { - - tmpChannelArray = OSArray::withCapacity(3); - - // Encapsulate the Channel ID in OSNumber - tmpChannelArray->setObject(kIOReportChannelIDIdx, channelIDs->getObject(cnt)); - - // Encapsulate the Channel Type in OSNumber - memcpy(&type64, &channelType, sizeof(type64)); - tmpNum = OSNumber::withNumber(type64, 64); - if (!tmpNum) { - goto finish; - } - tmpChannelArray->setObject(kIOReportChannelTypeIdx, tmpNum); - tmpNum->release(); - - // Encapsulate the Channel Name in OSSymbol - // Use channelNames if provided - if (channelNames != NULL) { - tmpSymbol = OSDynamicCast(OSSymbol, channelNames->getObject(cnt)); - if (tmpSymbol && tmpSymbol != gIOReportNoChannelName) { - tmpChannelArray->setObject(kIOReportChannelNameIdx, tmpSymbol); - } // Else, skip and leave name field empty - } - - channelLegendArray->setObject(cnt, tmpChannelArray); - tmpChannelArray->release(); - tmpChannelArray = NULL; - } - - // Stuff the legend entry only if we have channels... - if (channelLegendArray->getCount() != 0) { - - channelInfoDict = OSDictionary::withCapacity(1); - - if (!channelInfoDict) { - goto finish; - } - - tmpNum = OSNumber::withNumber(unit, 64); - if (tmpNum) { - channelInfoDict->setObject(kIOReportLegendUnitKey, tmpNum); - tmpNum->release(); - } - - legendEntry = OSDictionary::withCapacity(1); - - if (legendEntry) { - legendEntry->setObject(kIOReportLegendChannelsKey, channelLegendArray); - legendEntry->setObject(kIOReportLegendInfoKey, channelInfoDict); - } - } - + unsigned int cnt, chCnt; + uint64_t type64; + OSNumber *tmpNum; + const OSSymbol *tmpSymbol; + OSArray *channelLegendArray = NULL, *tmpChannelArray = NULL; + OSDictionary *channelInfoDict = NULL; + IOReportLegendEntry *legendEntry = NULL; + + // No need to check validity of channelNames because param is optional + if (!channelIDs) { + goto finish; + } + chCnt = channelIDs->getCount(); + + channelLegendArray = OSArray::withCapacity(chCnt); + + for (cnt = 0; cnt < chCnt; cnt++) { + tmpChannelArray = OSArray::withCapacity(3); + + // Encapsulate the Channel ID in OSNumber + tmpChannelArray->setObject(kIOReportChannelIDIdx, channelIDs->getObject(cnt)); + + // Encapsulate the Channel Type in OSNumber + memcpy(&type64, &channelType, sizeof(type64)); + tmpNum = OSNumber::withNumber(type64, 64); + if (!tmpNum) { + goto finish; + } + tmpChannelArray->setObject(kIOReportChannelTypeIdx, tmpNum); + tmpNum->release(); + + // Encapsulate the Channel Name in OSSymbol + // Use channelNames if provided + if (channelNames != NULL) { + tmpSymbol = OSDynamicCast(OSSymbol, channelNames->getObject(cnt)); + if (tmpSymbol && tmpSymbol != gIOReportNoChannelName) { + tmpChannelArray->setObject(kIOReportChannelNameIdx, tmpSymbol); + } // Else, skip and leave name field empty + } + + channelLegendArray->setObject(cnt, tmpChannelArray); + tmpChannelArray->release(); + tmpChannelArray = NULL; + } + + // Stuff the legend entry only if we have channels... + if (channelLegendArray->getCount() != 0) { + channelInfoDict = OSDictionary::withCapacity(1); + + if (!channelInfoDict) { + goto finish; + } + + tmpNum = OSNumber::withNumber(unit, 64); + if (tmpNum) { + channelInfoDict->setObject(kIOReportLegendUnitKey, tmpNum); + tmpNum->release(); + } + + legendEntry = OSDictionary::withCapacity(1); + + if (legendEntry) { + legendEntry->setObject(kIOReportLegendChannelsKey, channelLegendArray); + legendEntry->setObject(kIOReportLegendInfoKey, channelInfoDict); + } + } + finish: - if (tmpChannelArray) tmpChannelArray->release(); - if (channelInfoDict) channelInfoDict->release(); - if (channelLegendArray) channelLegendArray->release(); - - return legendEntry; + if (tmpChannelArray) { + tmpChannelArray->release(); + } + if (channelInfoDict) { + channelInfoDict->release(); + } + if (channelLegendArray) { + channelLegendArray->release(); + } + + return legendEntry; }