1 /****************************************************************************** 2 * 3 * Module Name: uttrack - Memory allocation tracking routines (debug only) 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2013, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 /* 45 * These procedures are used for tracking memory leaks in the subsystem, and 46 * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set. 47 * 48 * Each memory allocation is tracked via a doubly linked list. Each 49 * element contains the caller's component, module name, function name, and 50 * line number. AcpiUtAllocate and AcpiUtAllocateZeroed call 51 * AcpiUtTrackAllocation to add an element to the list; deletion 52 * occurs in the body of AcpiUtFree. 53 */ 54 55 #define __UTTRACK_C__ 56 57 #include <contrib/dev/acpica/include/acpi.h> 58 #include <contrib/dev/acpica/include/accommon.h> 59 60 #ifdef ACPI_DBG_TRACK_ALLOCATIONS 61 62 #define _COMPONENT ACPI_UTILITIES 63 ACPI_MODULE_NAME ("uttrack") 64 65 66 /* Local prototypes */ 67 68 static ACPI_DEBUG_MEM_BLOCK * 69 AcpiUtFindAllocation ( 70 ACPI_DEBUG_MEM_BLOCK *Allocation); 71 72 static ACPI_STATUS 73 AcpiUtTrackAllocation ( 74 ACPI_DEBUG_MEM_BLOCK *Address, 75 ACPI_SIZE Size, 76 UINT8 AllocType, 77 UINT32 Component, 78 const char *Module, 79 UINT32 Line); 80 81 static ACPI_STATUS 82 AcpiUtRemoveAllocation ( 83 ACPI_DEBUG_MEM_BLOCK *Address, 84 UINT32 Component, 85 const char *Module, 86 UINT32 Line); 87 88 89 /******************************************************************************* 90 * 91 * FUNCTION: AcpiUtCreateList 92 * 93 * PARAMETERS: CacheName - Ascii name for the cache 94 * ObjectSize - Size of each cached object 95 * ReturnCache - Where the new cache object is returned 96 * 97 * RETURN: Status 98 * 99 * DESCRIPTION: Create a local memory list for tracking purposed 100 * 101 ******************************************************************************/ 102 103 ACPI_STATUS 104 AcpiUtCreateList ( 105 char *ListName, 106 UINT16 ObjectSize, 107 ACPI_MEMORY_LIST **ReturnCache) 108 { 109 ACPI_MEMORY_LIST *Cache; 110 111 112 Cache = AcpiOsAllocate (sizeof (ACPI_MEMORY_LIST)); 113 if (!Cache) 114 { 115 return (AE_NO_MEMORY); 116 } 117 118 ACPI_MEMSET (Cache, 0, sizeof (ACPI_MEMORY_LIST)); 119 120 Cache->ListName = ListName; 121 Cache->ObjectSize = ObjectSize; 122 123 *ReturnCache = Cache; 124 return (AE_OK); 125 } 126 127 128 /******************************************************************************* 129 * 130 * FUNCTION: AcpiUtAllocateAndTrack 131 * 132 * PARAMETERS: Size - Size of the allocation 133 * Component - Component type of caller 134 * Module - Source file name of caller 135 * Line - Line number of caller 136 * 137 * RETURN: Address of the allocated memory on success, NULL on failure. 138 * 139 * DESCRIPTION: The subsystem's equivalent of malloc. 140 * 141 ******************************************************************************/ 142 143 void * 144 AcpiUtAllocateAndTrack ( 145 ACPI_SIZE Size, 146 UINT32 Component, 147 const char *Module, 148 UINT32 Line) 149 { 150 ACPI_DEBUG_MEM_BLOCK *Allocation; 151 ACPI_STATUS Status; 152 153 154 Allocation = AcpiUtAllocate (Size + sizeof (ACPI_DEBUG_MEM_HEADER), 155 Component, Module, Line); 156 if (!Allocation) 157 { 158 return (NULL); 159 } 160 161 Status = AcpiUtTrackAllocation (Allocation, Size, 162 ACPI_MEM_MALLOC, Component, Module, Line); 163 if (ACPI_FAILURE (Status)) 164 { 165 AcpiOsFree (Allocation); 166 return (NULL); 167 } 168 169 AcpiGbl_GlobalList->TotalAllocated++; 170 AcpiGbl_GlobalList->TotalSize += (UINT32) Size; 171 AcpiGbl_GlobalList->CurrentTotalSize += (UINT32) Size; 172 if (AcpiGbl_GlobalList->CurrentTotalSize > AcpiGbl_GlobalList->MaxOccupied) 173 { 174 AcpiGbl_GlobalList->MaxOccupied = AcpiGbl_GlobalList->CurrentTotalSize; 175 } 176 177 return ((void *) &Allocation->UserSpace); 178 } 179 180 181 /******************************************************************************* 182 * 183 * FUNCTION: AcpiUtAllocateZeroedAndTrack 184 * 185 * PARAMETERS: Size - Size of the allocation 186 * Component - Component type of caller 187 * Module - Source file name of caller 188 * Line - Line number of caller 189 * 190 * RETURN: Address of the allocated memory on success, NULL on failure. 191 * 192 * DESCRIPTION: Subsystem equivalent of calloc. 193 * 194 ******************************************************************************/ 195 196 void * 197 AcpiUtAllocateZeroedAndTrack ( 198 ACPI_SIZE Size, 199 UINT32 Component, 200 const char *Module, 201 UINT32 Line) 202 { 203 ACPI_DEBUG_MEM_BLOCK *Allocation; 204 ACPI_STATUS Status; 205 206 207 Allocation = AcpiUtAllocateZeroed (Size + sizeof (ACPI_DEBUG_MEM_HEADER), 208 Component, Module, Line); 209 if (!Allocation) 210 { 211 /* Report allocation error */ 212 213 ACPI_ERROR ((Module, Line, 214 "Could not allocate size %u", (UINT32) Size)); 215 return (NULL); 216 } 217 218 Status = AcpiUtTrackAllocation (Allocation, Size, 219 ACPI_MEM_CALLOC, Component, Module, Line); 220 if (ACPI_FAILURE (Status)) 221 { 222 AcpiOsFree (Allocation); 223 return (NULL); 224 } 225 226 AcpiGbl_GlobalList->TotalAllocated++; 227 AcpiGbl_GlobalList->TotalSize += (UINT32) Size; 228 AcpiGbl_GlobalList->CurrentTotalSize += (UINT32) Size; 229 if (AcpiGbl_GlobalList->CurrentTotalSize > AcpiGbl_GlobalList->MaxOccupied) 230 { 231 AcpiGbl_GlobalList->MaxOccupied = AcpiGbl_GlobalList->CurrentTotalSize; 232 } 233 234 return ((void *) &Allocation->UserSpace); 235 } 236 237 238 /******************************************************************************* 239 * 240 * FUNCTION: AcpiUtFreeAndTrack 241 * 242 * PARAMETERS: Allocation - Address of the memory to deallocate 243 * Component - Component type of caller 244 * Module - Source file name of caller 245 * Line - Line number of caller 246 * 247 * RETURN: None 248 * 249 * DESCRIPTION: Frees the memory at Allocation 250 * 251 ******************************************************************************/ 252 253 void 254 AcpiUtFreeAndTrack ( 255 void *Allocation, 256 UINT32 Component, 257 const char *Module, 258 UINT32 Line) 259 { 260 ACPI_DEBUG_MEM_BLOCK *DebugBlock; 261 ACPI_STATUS Status; 262 263 264 ACPI_FUNCTION_TRACE_PTR (UtFree, Allocation); 265 266 267 if (NULL == Allocation) 268 { 269 ACPI_ERROR ((Module, Line, 270 "Attempt to delete a NULL address")); 271 272 return_VOID; 273 } 274 275 DebugBlock = ACPI_CAST_PTR (ACPI_DEBUG_MEM_BLOCK, 276 (((char *) Allocation) - sizeof (ACPI_DEBUG_MEM_HEADER))); 277 278 AcpiGbl_GlobalList->TotalFreed++; 279 AcpiGbl_GlobalList->CurrentTotalSize -= DebugBlock->Size; 280 281 Status = AcpiUtRemoveAllocation (DebugBlock, 282 Component, Module, Line); 283 if (ACPI_FAILURE (Status)) 284 { 285 ACPI_EXCEPTION ((AE_INFO, Status, "Could not free memory")); 286 } 287 288 AcpiOsFree (DebugBlock); 289 ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p freed\n", Allocation)); 290 return_VOID; 291 } 292 293 294 /******************************************************************************* 295 * 296 * FUNCTION: AcpiUtFindAllocation 297 * 298 * PARAMETERS: Allocation - Address of allocated memory 299 * 300 * RETURN: Three cases: 301 * 1) List is empty, NULL is returned. 302 * 2) Element was found. Returns Allocation parameter. 303 * 3) Element was not found. Returns position where it should be 304 * inserted into the list. 305 * 306 * DESCRIPTION: Searches for an element in the global allocation tracking list. 307 * If the element is not found, returns the location within the 308 * list where the element should be inserted. 309 * 310 * Note: The list is ordered by larger-to-smaller addresses. 311 * 312 * This global list is used to detect memory leaks in ACPICA as 313 * well as other issues such as an attempt to release the same 314 * internal object more than once. Although expensive as far 315 * as cpu time, this list is much more helpful for finding these 316 * types of issues than using memory leak detectors outside of 317 * the ACPICA code. 318 * 319 ******************************************************************************/ 320 321 static ACPI_DEBUG_MEM_BLOCK * 322 AcpiUtFindAllocation ( 323 ACPI_DEBUG_MEM_BLOCK *Allocation) 324 { 325 ACPI_DEBUG_MEM_BLOCK *Element; 326 327 328 Element = AcpiGbl_GlobalList->ListHead; 329 if (!Element) 330 { 331 return (NULL); 332 } 333 334 /* 335 * Search for the address. 336 * 337 * Note: List is ordered by larger-to-smaller addresses, on the 338 * assumption that a new allocation usually has a larger address 339 * than previous allocations. 340 */ 341 while (Element > Allocation) 342 { 343 /* Check for end-of-list */ 344 345 if (!Element->Next) 346 { 347 return (Element); 348 } 349 350 Element = Element->Next; 351 } 352 353 if (Element == Allocation) 354 { 355 return (Element); 356 } 357 358 return (Element->Previous); 359 } 360 361 362 /******************************************************************************* 363 * 364 * FUNCTION: AcpiUtTrackAllocation 365 * 366 * PARAMETERS: Allocation - Address of allocated memory 367 * Size - Size of the allocation 368 * AllocType - MEM_MALLOC or MEM_CALLOC 369 * Component - Component type of caller 370 * Module - Source file name of caller 371 * Line - Line number of caller 372 * 373 * RETURN: Status 374 * 375 * DESCRIPTION: Inserts an element into the global allocation tracking list. 376 * 377 ******************************************************************************/ 378 379 static ACPI_STATUS 380 AcpiUtTrackAllocation ( 381 ACPI_DEBUG_MEM_BLOCK *Allocation, 382 ACPI_SIZE Size, 383 UINT8 AllocType, 384 UINT32 Component, 385 const char *Module, 386 UINT32 Line) 387 { 388 ACPI_MEMORY_LIST *MemList; 389 ACPI_DEBUG_MEM_BLOCK *Element; 390 ACPI_STATUS Status = AE_OK; 391 392 393 ACPI_FUNCTION_TRACE_PTR (UtTrackAllocation, Allocation); 394 395 396 if (AcpiGbl_DisableMemTracking) 397 { 398 return_ACPI_STATUS (AE_OK); 399 } 400 401 MemList = AcpiGbl_GlobalList; 402 Status = AcpiUtAcquireMutex (ACPI_MTX_MEMORY); 403 if (ACPI_FAILURE (Status)) 404 { 405 return_ACPI_STATUS (Status); 406 } 407 408 /* 409 * Search the global list for this address to make sure it is not 410 * already present. This will catch several kinds of problems. 411 */ 412 Element = AcpiUtFindAllocation (Allocation); 413 if (Element == Allocation) 414 { 415 ACPI_ERROR ((AE_INFO, 416 "UtTrackAllocation: Allocation (%p) already present in global list!", 417 Allocation)); 418 goto UnlockAndExit; 419 } 420 421 /* Fill in the instance data */ 422 423 Allocation->Size = (UINT32) Size; 424 Allocation->AllocType = AllocType; 425 Allocation->Component = Component; 426 Allocation->Line = Line; 427 428 ACPI_STRNCPY (Allocation->Module, Module, ACPI_MAX_MODULE_NAME); 429 Allocation->Module[ACPI_MAX_MODULE_NAME-1] = 0; 430 431 if (!Element) 432 { 433 /* Insert at list head */ 434 435 if (MemList->ListHead) 436 { 437 ((ACPI_DEBUG_MEM_BLOCK *)(MemList->ListHead))->Previous = Allocation; 438 } 439 440 Allocation->Next = MemList->ListHead; 441 Allocation->Previous = NULL; 442 443 MemList->ListHead = Allocation; 444 } 445 else 446 { 447 /* Insert after element */ 448 449 Allocation->Next = Element->Next; 450 Allocation->Previous = Element; 451 452 if (Element->Next) 453 { 454 (Element->Next)->Previous = Allocation; 455 } 456 457 Element->Next = Allocation; 458 } 459 460 461 UnlockAndExit: 462 Status = AcpiUtReleaseMutex (ACPI_MTX_MEMORY); 463 return_ACPI_STATUS (Status); 464 } 465 466 467 /******************************************************************************* 468 * 469 * FUNCTION: AcpiUtRemoveAllocation 470 * 471 * PARAMETERS: Allocation - Address of allocated memory 472 * Component - Component type of caller 473 * Module - Source file name of caller 474 * Line - Line number of caller 475 * 476 * RETURN: Status 477 * 478 * DESCRIPTION: Deletes an element from the global allocation tracking list. 479 * 480 ******************************************************************************/ 481 482 static ACPI_STATUS 483 AcpiUtRemoveAllocation ( 484 ACPI_DEBUG_MEM_BLOCK *Allocation, 485 UINT32 Component, 486 const char *Module, 487 UINT32 Line) 488 { 489 ACPI_MEMORY_LIST *MemList; 490 ACPI_STATUS Status; 491 492 493 ACPI_FUNCTION_NAME (UtRemoveAllocation); 494 495 496 if (AcpiGbl_DisableMemTracking) 497 { 498 return (AE_OK); 499 } 500 501 MemList = AcpiGbl_GlobalList; 502 if (NULL == MemList->ListHead) 503 { 504 /* No allocations! */ 505 506 ACPI_ERROR ((Module, Line, 507 "Empty allocation list, nothing to free!")); 508 509 return (AE_OK); 510 } 511 512 Status = AcpiUtAcquireMutex (ACPI_MTX_MEMORY); 513 if (ACPI_FAILURE (Status)) 514 { 515 return (Status); 516 } 517 518 /* Unlink */ 519 520 if (Allocation->Previous) 521 { 522 (Allocation->Previous)->Next = Allocation->Next; 523 } 524 else 525 { 526 MemList->ListHead = Allocation->Next; 527 } 528 529 if (Allocation->Next) 530 { 531 (Allocation->Next)->Previous = Allocation->Previous; 532 } 533 534 ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing %p, size 0%X\n", 535 &Allocation->UserSpace, Allocation->Size)); 536 537 /* Mark the segment as deleted */ 538 539 ACPI_MEMSET (&Allocation->UserSpace, 0xEA, Allocation->Size); 540 541 Status = AcpiUtReleaseMutex (ACPI_MTX_MEMORY); 542 return (Status); 543 } 544 545 546 /******************************************************************************* 547 * 548 * FUNCTION: AcpiUtDumpAllocationInfo 549 * 550 * PARAMETERS: None 551 * 552 * RETURN: None 553 * 554 * DESCRIPTION: Print some info about the outstanding allocations. 555 * 556 ******************************************************************************/ 557 558 void 559 AcpiUtDumpAllocationInfo ( 560 void) 561 { 562 /* 563 ACPI_MEMORY_LIST *MemList; 564 */ 565 566 ACPI_FUNCTION_TRACE (UtDumpAllocationInfo); 567 568 /* 569 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 570 ("%30s: %4d (%3d Kb)\n", "Current allocations", 571 MemList->CurrentCount, 572 ROUND_UP_TO_1K (MemList->CurrentSize))); 573 574 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 575 ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations", 576 MemList->MaxConcurrentCount, 577 ROUND_UP_TO_1K (MemList->MaxConcurrentSize))); 578 579 580 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 581 ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects", 582 RunningObjectCount, 583 ROUND_UP_TO_1K (RunningObjectSize))); 584 585 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 586 ("%30s: %4d (%3d Kb)\n", "Total (all) allocations", 587 RunningAllocCount, 588 ROUND_UP_TO_1K (RunningAllocSize))); 589 590 591 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 592 ("%30s: %4d (%3d Kb)\n", "Current Nodes", 593 AcpiGbl_CurrentNodeCount, 594 ROUND_UP_TO_1K (AcpiGbl_CurrentNodeSize))); 595 596 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 597 ("%30s: %4d (%3d Kb)\n", "Max Nodes", 598 AcpiGbl_MaxConcurrentNodeCount, 599 ROUND_UP_TO_1K ((AcpiGbl_MaxConcurrentNodeCount * 600 sizeof (ACPI_NAMESPACE_NODE))))); 601 */ 602 return_VOID; 603 } 604 605 606 /******************************************************************************* 607 * 608 * FUNCTION: AcpiUtDumpAllocations 609 * 610 * PARAMETERS: Component - Component(s) to dump info for. 611 * Module - Module to dump info for. NULL means all. 612 * 613 * RETURN: None 614 * 615 * DESCRIPTION: Print a list of all outstanding allocations. 616 * 617 ******************************************************************************/ 618 619 void 620 AcpiUtDumpAllocations ( 621 UINT32 Component, 622 const char *Module) 623 { 624 ACPI_DEBUG_MEM_BLOCK *Element; 625 ACPI_DESCRIPTOR *Descriptor; 626 UINT32 NumOutstanding = 0; 627 UINT8 DescriptorType; 628 629 630 ACPI_FUNCTION_TRACE (UtDumpAllocations); 631 632 633 if (AcpiGbl_DisableMemTracking) 634 { 635 return_VOID; 636 } 637 638 /* 639 * Walk the allocation list. 640 */ 641 if (ACPI_FAILURE (AcpiUtAcquireMutex (ACPI_MTX_MEMORY))) 642 { 643 return_VOID; 644 } 645 646 Element = AcpiGbl_GlobalList->ListHead; 647 while (Element) 648 { 649 if ((Element->Component & Component) && 650 ((Module == NULL) || (0 == ACPI_STRCMP (Module, Element->Module)))) 651 { 652 Descriptor = ACPI_CAST_PTR (ACPI_DESCRIPTOR, &Element->UserSpace); 653 654 if (Element->Size < sizeof (ACPI_COMMON_DESCRIPTOR)) 655 { 656 AcpiOsPrintf ("%p Length 0x%04X %9.9s-%u " 657 "[Not a Descriptor - too small]\n", 658 Descriptor, Element->Size, Element->Module, 659 Element->Line); 660 } 661 else 662 { 663 /* Ignore allocated objects that are in a cache */ 664 665 if (ACPI_GET_DESCRIPTOR_TYPE (Descriptor) != ACPI_DESC_TYPE_CACHED) 666 { 667 AcpiOsPrintf ("%p Length 0x%04X %9.9s-%u [%s] ", 668 Descriptor, Element->Size, Element->Module, 669 Element->Line, AcpiUtGetDescriptorName (Descriptor)); 670 671 /* Validate the descriptor type using Type field and length */ 672 673 DescriptorType = 0; /* Not a valid descriptor type */ 674 675 switch (ACPI_GET_DESCRIPTOR_TYPE (Descriptor)) 676 { 677 case ACPI_DESC_TYPE_OPERAND: 678 679 if (Element->Size == sizeof (ACPI_OPERAND_OBJECT)) 680 { 681 DescriptorType = ACPI_DESC_TYPE_OPERAND; 682 } 683 break; 684 685 case ACPI_DESC_TYPE_PARSER: 686 687 if (Element->Size == sizeof (ACPI_PARSE_OBJECT)) 688 { 689 DescriptorType = ACPI_DESC_TYPE_PARSER; 690 } 691 break; 692 693 case ACPI_DESC_TYPE_NAMED: 694 695 if (Element->Size == sizeof (ACPI_NAMESPACE_NODE)) 696 { 697 DescriptorType = ACPI_DESC_TYPE_NAMED; 698 } 699 break; 700 701 default: 702 703 break; 704 } 705 706 /* Display additional info for the major descriptor types */ 707 708 switch (DescriptorType) 709 { 710 case ACPI_DESC_TYPE_OPERAND: 711 712 AcpiOsPrintf ("%12.12s RefCount 0x%04X\n", 713 AcpiUtGetTypeName (Descriptor->Object.Common.Type), 714 Descriptor->Object.Common.ReferenceCount); 715 break; 716 717 case ACPI_DESC_TYPE_PARSER: 718 719 AcpiOsPrintf ("AmlOpcode 0x%04hX\n", 720 Descriptor->Op.Asl.AmlOpcode); 721 break; 722 723 case ACPI_DESC_TYPE_NAMED: 724 725 AcpiOsPrintf ("%4.4s\n", 726 AcpiUtGetNodeName (&Descriptor->Node)); 727 break; 728 729 default: 730 731 AcpiOsPrintf ( "\n"); 732 break; 733 } 734 } 735 } 736 737 NumOutstanding++; 738 } 739 740 Element = Element->Next; 741 } 742 743 (void) AcpiUtReleaseMutex (ACPI_MTX_MEMORY); 744 745 /* Print summary */ 746 747 if (!NumOutstanding) 748 { 749 ACPI_INFO ((AE_INFO, "No outstanding allocations")); 750 } 751 else 752 { 753 ACPI_ERROR ((AE_INFO, "%u(0x%X) Outstanding allocations", 754 NumOutstanding, NumOutstanding)); 755 } 756 757 return_VOID; 758 } 759 760 #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ 761