1 /*******************************************************************************
3 * Module Name: dbexec - debugger control method execution
5 ******************************************************************************/
8 * Copyright (C) 2000 - 2016, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
51 #define _COMPONENT ACPI_CA_DEBUGGER
52 ACPI_MODULE_NAME ("dbexec")
55 static ACPI_DB_METHOD_INFO AcpiGbl_DbMethodInfo
;
57 /* Local prototypes */
61 ACPI_DB_METHOD_INFO
*Info
,
62 ACPI_BUFFER
*ReturnObj
);
66 ACPI_DB_METHOD_INFO
*Info
);
69 AcpiDbGetOutstandingAllocations (
72 static void ACPI_SYSTEM_XFACE
78 ACPI_HANDLE ObjHandle
,
84 /*******************************************************************************
86 * FUNCTION: AcpiDbDeleteObjects
88 * PARAMETERS: Count - Count of objects in the list
89 * Objects - Array of ACPI_OBJECTs to be deleted
93 * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
94 * packages via recursion.
96 ******************************************************************************/
101 ACPI_OBJECT
*Objects
)
106 for (i
= 0; i
< Count
; i
++)
108 switch (Objects
[i
].Type
)
110 case ACPI_TYPE_BUFFER
:
112 ACPI_FREE (Objects
[i
].Buffer
.Pointer
);
115 case ACPI_TYPE_PACKAGE
:
117 /* Recursive call to delete package elements */
119 AcpiDbDeleteObjects (Objects
[i
].Package
.Count
,
120 Objects
[i
].Package
.Elements
);
122 /* Free the elements array */
124 ACPI_FREE (Objects
[i
].Package
.Elements
);
135 /*******************************************************************************
137 * FUNCTION: AcpiDbExecuteMethod
139 * PARAMETERS: Info - Valid info segment
140 * ReturnObj - Where to put return object
144 * DESCRIPTION: Execute a control method.
146 ******************************************************************************/
149 AcpiDbExecuteMethod (
150 ACPI_DB_METHOD_INFO
*Info
,
151 ACPI_BUFFER
*ReturnObj
)
154 ACPI_OBJECT_LIST ParamObjects
;
155 ACPI_OBJECT Params
[ACPI_DEBUGGER_MAX_ARGS
+ 1];
159 ACPI_FUNCTION_TRACE (DbExecuteMethod
);
162 if (AcpiGbl_DbOutputToFile
&& !AcpiDbgLevel
)
164 AcpiOsPrintf ("Warning: debug output is not enabled!\n");
167 ParamObjects
.Count
= 0;
168 ParamObjects
.Pointer
= NULL
;
170 /* Pass through any command-line arguments */
172 if (Info
->Args
&& Info
->Args
[0])
174 /* Get arguments passed on the command line */
176 for (i
= 0; (Info
->Args
[i
] && *(Info
->Args
[i
])); i
++)
178 /* Convert input string (token) to an actual ACPI_OBJECT */
180 Status
= AcpiDbConvertToObject (Info
->Types
[i
],
181 Info
->Args
[i
], &Params
[i
]);
182 if (ACPI_FAILURE (Status
))
184 ACPI_EXCEPTION ((AE_INFO
, Status
,
185 "While parsing method arguments"));
190 ParamObjects
.Count
= i
;
191 ParamObjects
.Pointer
= Params
;
194 /* Prepare for a return object of arbitrary size */
196 ReturnObj
->Pointer
= AcpiGbl_DbBuffer
;
197 ReturnObj
->Length
= ACPI_DEBUG_BUFFER_SIZE
;
199 /* Do the actual method execution */
201 AcpiGbl_MethodExecuting
= TRUE
;
202 Status
= AcpiEvaluateObject (NULL
, Info
->Pathname
,
203 &ParamObjects
, ReturnObj
);
205 AcpiGbl_CmSingleStep
= FALSE
;
206 AcpiGbl_MethodExecuting
= FALSE
;
208 if (ACPI_FAILURE (Status
))
210 ACPI_EXCEPTION ((AE_INFO
, Status
,
211 "while executing %s from debugger", Info
->Pathname
));
213 if (Status
== AE_BUFFER_OVERFLOW
)
215 ACPI_ERROR ((AE_INFO
,
216 "Possible overflow of internal debugger "
217 "buffer (size 0x%X needed 0x%X)",
218 ACPI_DEBUG_BUFFER_SIZE
, (UINT32
) ReturnObj
->Length
));
223 AcpiDbDeleteObjects (ParamObjects
.Count
, Params
);
224 return_ACPI_STATUS (Status
);
228 /*******************************************************************************
230 * FUNCTION: AcpiDbExecuteSetup
232 * PARAMETERS: Info - Valid method info
236 * DESCRIPTION: Setup info segment prior to method execution
238 ******************************************************************************/
242 ACPI_DB_METHOD_INFO
*Info
)
247 ACPI_FUNCTION_NAME (DbExecuteSetup
);
250 /* Catenate the current scope to the supplied name */
252 Info
->Pathname
[0] = 0;
253 if ((Info
->Name
[0] != '\\') &&
254 (Info
->Name
[0] != '/'))
256 if (AcpiUtSafeStrcat (Info
->Pathname
, sizeof (Info
->Pathname
),
259 Status
= AE_BUFFER_OVERFLOW
;
264 if (AcpiUtSafeStrcat (Info
->Pathname
, sizeof (Info
->Pathname
),
267 Status
= AE_BUFFER_OVERFLOW
;
271 AcpiDbPrepNamestring (Info
->Pathname
);
273 AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT
);
274 AcpiOsPrintf ("Evaluating %s\n", Info
->Pathname
);
276 if (Info
->Flags
& EX_SINGLE_STEP
)
278 AcpiGbl_CmSingleStep
= TRUE
;
279 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT
);
284 /* No single step, allow redirection to a file */
286 AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT
);
293 ACPI_EXCEPTION ((AE_INFO
, Status
, "During setup for method execution"));
298 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
301 ACPI_MEMORY_LIST
*Cache
)
304 return (Cache
->TotalAllocated
- Cache
->TotalFreed
- Cache
->CurrentDepth
);
308 /*******************************************************************************
310 * FUNCTION: AcpiDbGetOutstandingAllocations
314 * RETURN: Current global allocation count minus cache entries
316 * DESCRIPTION: Determine the current number of "outstanding" allocations --
317 * those allocations that have not been freed and also are not
318 * in one of the various object caches.
320 ******************************************************************************/
323 AcpiDbGetOutstandingAllocations (
326 UINT32 Outstanding
= 0;
328 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
330 Outstanding
+= AcpiDbGetCacheInfo (AcpiGbl_StateCache
);
331 Outstanding
+= AcpiDbGetCacheInfo (AcpiGbl_PsNodeCache
);
332 Outstanding
+= AcpiDbGetCacheInfo (AcpiGbl_PsNodeExtCache
);
333 Outstanding
+= AcpiDbGetCacheInfo (AcpiGbl_OperandCache
);
336 return (Outstanding
);
340 /*******************************************************************************
342 * FUNCTION: AcpiDbExecutionWalk
344 * PARAMETERS: WALK_CALLBACK
348 * DESCRIPTION: Execute a control method. Name is relative to the current
351 ******************************************************************************/
354 AcpiDbExecutionWalk (
355 ACPI_HANDLE ObjHandle
,
360 ACPI_OPERAND_OBJECT
*ObjDesc
;
361 ACPI_NAMESPACE_NODE
*Node
= (ACPI_NAMESPACE_NODE
*) ObjHandle
;
362 ACPI_BUFFER ReturnObj
;
366 ObjDesc
= AcpiNsGetAttachedObject (Node
);
367 if (ObjDesc
->Method
.ParamCount
)
372 ReturnObj
.Pointer
= NULL
;
373 ReturnObj
.Length
= ACPI_ALLOCATE_BUFFER
;
375 AcpiNsPrintNodePathname (Node
, "Evaluating");
377 /* Do the actual method execution */
380 AcpiGbl_MethodExecuting
= TRUE
;
382 Status
= AcpiEvaluateObject (Node
, NULL
, NULL
, &ReturnObj
);
384 AcpiOsPrintf ("Evaluation of [%4.4s] returned %s\n",
385 AcpiUtGetNodeName (Node
),
386 AcpiFormatException (Status
));
388 AcpiGbl_MethodExecuting
= FALSE
;
393 /*******************************************************************************
395 * FUNCTION: AcpiDbExecute
397 * PARAMETERS: Name - Name of method to execute
398 * Args - Parameters to the method
400 * Flags - single step/no single step
404 * DESCRIPTION: Execute a control method. Name is relative to the current
407 ******************************************************************************/
413 ACPI_OBJECT_TYPE
*Types
,
417 ACPI_BUFFER ReturnObj
;
420 #ifdef ACPI_DEBUG_OUTPUT
421 UINT32 PreviousAllocations
;
427 * Allow one execution to be performed by debugger or single step
428 * execution will be dead locked by the interpreter mutexes.
430 if (AcpiGbl_MethodExecuting
)
432 AcpiOsPrintf ("Only one debugger execution is allowed.\n");
436 #ifdef ACPI_DEBUG_OUTPUT
437 /* Memory allocation tracking */
439 PreviousAllocations
= AcpiDbGetOutstandingAllocations ();
444 (void) AcpiWalkNamespace (ACPI_TYPE_METHOD
, ACPI_ROOT_OBJECT
,
445 ACPI_UINT32_MAX
, AcpiDbExecutionWalk
, NULL
, NULL
, NULL
);
449 NameString
= ACPI_ALLOCATE (strlen (Name
) + 1);
455 memset (&AcpiGbl_DbMethodInfo
, 0, sizeof (ACPI_DB_METHOD_INFO
));
456 strcpy (NameString
, Name
);
457 AcpiUtStrupr (NameString
);
459 /* Subcommand to Execute all predefined names in the namespace */
461 if (!strncmp (NameString
, "PREDEF", 6))
463 AcpiDbEvaluatePredefinedNames ();
464 ACPI_FREE (NameString
);
468 AcpiGbl_DbMethodInfo
.Name
= NameString
;
469 AcpiGbl_DbMethodInfo
.Args
= Args
;
470 AcpiGbl_DbMethodInfo
.Types
= Types
;
471 AcpiGbl_DbMethodInfo
.Flags
= Flags
;
473 ReturnObj
.Pointer
= NULL
;
474 ReturnObj
.Length
= ACPI_ALLOCATE_BUFFER
;
476 Status
= AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo
);
477 if (ACPI_FAILURE (Status
))
479 ACPI_FREE (NameString
);
483 /* Get the NS node, determines existence also */
485 Status
= AcpiGetHandle (NULL
, AcpiGbl_DbMethodInfo
.Pathname
,
486 &AcpiGbl_DbMethodInfo
.Method
);
487 if (ACPI_SUCCESS (Status
))
489 Status
= AcpiDbExecuteMethod (&AcpiGbl_DbMethodInfo
,
492 ACPI_FREE (NameString
);
495 * Allow any handlers in separate threads to complete.
496 * (Such as Notify handlers invoked from AML executed above).
498 AcpiOsSleep ((UINT64
) 10);
500 #ifdef ACPI_DEBUG_OUTPUT
502 /* Memory allocation tracking */
504 Allocations
= AcpiDbGetOutstandingAllocations () - PreviousAllocations
;
506 AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT
);
511 "0x%X Outstanding allocations after evaluation of %s\n",
512 Allocations
, AcpiGbl_DbMethodInfo
.Pathname
);
516 if (ACPI_FAILURE (Status
))
518 AcpiOsPrintf ("Evaluation of %s failed with status %s\n",
519 AcpiGbl_DbMethodInfo
.Pathname
,
520 AcpiFormatException (Status
));
524 /* Display a return object, if any */
526 if (ReturnObj
.Length
)
529 "Evaluation of %s returned object %p, "
530 "external buffer length %X\n",
531 AcpiGbl_DbMethodInfo
.Pathname
, ReturnObj
.Pointer
,
532 (UINT32
) ReturnObj
.Length
);
534 AcpiDbDumpExternalObject (ReturnObj
.Pointer
, 1);
536 /* Dump a _PLD buffer if present */
538 if (ACPI_COMPARE_NAME ((ACPI_CAST_PTR (ACPI_NAMESPACE_NODE
,
539 AcpiGbl_DbMethodInfo
.Method
)->Name
.Ascii
),
542 AcpiDbDumpPldBuffer (ReturnObj
.Pointer
);
547 AcpiOsPrintf ("No object was returned from evaluation of %s\n",
548 AcpiGbl_DbMethodInfo
.Pathname
);
552 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT
);
556 /*******************************************************************************
558 * FUNCTION: AcpiDbMethodThread
560 * PARAMETERS: Context - Execution info segment
564 * DESCRIPTION: Debugger execute thread. Waits for a command line, then
565 * simply dispatches it.
567 ******************************************************************************/
569 static void ACPI_SYSTEM_XFACE
574 ACPI_DB_METHOD_INFO
*Info
= Context
;
575 ACPI_DB_METHOD_INFO LocalInfo
;
578 ACPI_BUFFER ReturnObj
;
582 * AcpiGbl_DbMethodInfo.Arguments will be passed as method arguments.
583 * Prevent AcpiGbl_DbMethodInfo from being modified by multiple threads
586 * Note: The arguments we are passing are used by the ASL test suite
587 * (aslts). Do not change them without updating the tests.
589 (void) AcpiOsWaitSemaphore (Info
->InfoGate
, 1, ACPI_WAIT_FOREVER
);
593 AcpiDbUint32ToHexString (Info
->NumCreated
,
594 Info
->IndexOfThreadStr
);
595 AcpiDbUint32ToHexString ((UINT32
) AcpiOsGetThreadId (),
596 Info
->IdOfThreadStr
);
599 if (Info
->Threads
&& (Info
->NumCreated
< Info
->NumThreads
))
601 Info
->Threads
[Info
->NumCreated
++] = AcpiOsGetThreadId();
605 LocalInfo
.Args
= LocalInfo
.Arguments
;
606 LocalInfo
.Arguments
[0] = LocalInfo
.NumThreadsStr
;
607 LocalInfo
.Arguments
[1] = LocalInfo
.IdOfThreadStr
;
608 LocalInfo
.Arguments
[2] = LocalInfo
.IndexOfThreadStr
;
609 LocalInfo
.Arguments
[3] = NULL
;
611 LocalInfo
.Types
= LocalInfo
.ArgTypes
;
613 (void) AcpiOsSignalSemaphore (Info
->InfoGate
, 1);
615 for (i
= 0; i
< Info
->NumLoops
; i
++)
617 Status
= AcpiDbExecuteMethod (&LocalInfo
, &ReturnObj
);
618 if (ACPI_FAILURE (Status
))
620 AcpiOsPrintf ("%s During evaluation of %s at iteration %X\n",
621 AcpiFormatException (Status
), Info
->Pathname
, i
);
622 if (Status
== AE_ABORT_METHOD
)
631 AcpiOsPrintf ("%u loops, Thread 0x%x\n",
632 i
, AcpiOsGetThreadId ());
635 if (ReturnObj
.Length
)
637 AcpiOsPrintf ("Evaluation of %s returned object %p Buflen %X\n",
638 Info
->Pathname
, ReturnObj
.Pointer
,
639 (UINT32
) ReturnObj
.Length
);
640 AcpiDbDumpExternalObject (ReturnObj
.Pointer
, 1);
645 /* Signal our completion */
648 (void) AcpiOsWaitSemaphore (Info
->ThreadCompleteGate
,
649 1, ACPI_WAIT_FOREVER
);
650 Info
->NumCompleted
++;
652 if (Info
->NumCompleted
== Info
->NumThreads
)
654 /* Do signal for main thread once only */
658 (void) AcpiOsSignalSemaphore (Info
->ThreadCompleteGate
, 1);
662 Status
= AcpiOsSignalSemaphore (Info
->MainThreadGate
, 1);
663 if (ACPI_FAILURE (Status
))
666 "Could not signal debugger thread sync semaphore, %s\n",
667 AcpiFormatException (Status
));
673 /*******************************************************************************
675 * FUNCTION: AcpiDbCreateExecutionThreads
677 * PARAMETERS: NumThreadsArg - Number of threads to create
678 * NumLoopsArg - Loop count for the thread(s)
679 * MethodNameArg - Control method to execute
683 * DESCRIPTION: Create threads to execute method(s)
685 ******************************************************************************/
688 AcpiDbCreateExecutionThreads (
698 ACPI_MUTEX MainThreadGate
;
699 ACPI_MUTEX ThreadCompleteGate
;
703 /* Get the arguments */
705 NumThreads
= strtoul (NumThreadsArg
, NULL
, 0);
706 NumLoops
= strtoul (NumLoopsArg
, NULL
, 0);
708 if (!NumThreads
|| !NumLoops
)
710 AcpiOsPrintf ("Bad argument: Threads %X, Loops %X\n",
711 NumThreads
, NumLoops
);
716 * Create the semaphore for synchronization of
717 * the created threads with the main thread.
719 Status
= AcpiOsCreateSemaphore (1, 0, &MainThreadGate
);
720 if (ACPI_FAILURE (Status
))
722 AcpiOsPrintf ("Could not create semaphore for "
723 "synchronization with the main thread, %s\n",
724 AcpiFormatException (Status
));
729 * Create the semaphore for synchronization
730 * between the created threads.
732 Status
= AcpiOsCreateSemaphore (1, 1, &ThreadCompleteGate
);
733 if (ACPI_FAILURE (Status
))
735 AcpiOsPrintf ("Could not create semaphore for "
736 "synchronization between the created threads, %s\n",
737 AcpiFormatException (Status
));
739 (void) AcpiOsDeleteSemaphore (MainThreadGate
);
743 Status
= AcpiOsCreateSemaphore (1, 1, &InfoGate
);
744 if (ACPI_FAILURE (Status
))
746 AcpiOsPrintf ("Could not create semaphore for "
747 "synchronization of AcpiGbl_DbMethodInfo, %s\n",
748 AcpiFormatException (Status
));
750 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate
);
751 (void) AcpiOsDeleteSemaphore (MainThreadGate
);
755 memset (&AcpiGbl_DbMethodInfo
, 0, sizeof (ACPI_DB_METHOD_INFO
));
757 /* Array to store IDs of threads */
759 AcpiGbl_DbMethodInfo
.NumThreads
= NumThreads
;
760 Size
= sizeof (ACPI_THREAD_ID
) * AcpiGbl_DbMethodInfo
.NumThreads
;
762 AcpiGbl_DbMethodInfo
.Threads
= AcpiOsAllocate (Size
);
763 if (AcpiGbl_DbMethodInfo
.Threads
== NULL
)
765 AcpiOsPrintf ("No memory for thread IDs array\n");
766 (void) AcpiOsDeleteSemaphore (MainThreadGate
);
767 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate
);
768 (void) AcpiOsDeleteSemaphore (InfoGate
);
771 memset (AcpiGbl_DbMethodInfo
.Threads
, 0, Size
);
773 /* Setup the context to be passed to each thread */
775 AcpiGbl_DbMethodInfo
.Name
= MethodNameArg
;
776 AcpiGbl_DbMethodInfo
.Flags
= 0;
777 AcpiGbl_DbMethodInfo
.NumLoops
= NumLoops
;
778 AcpiGbl_DbMethodInfo
.MainThreadGate
= MainThreadGate
;
779 AcpiGbl_DbMethodInfo
.ThreadCompleteGate
= ThreadCompleteGate
;
780 AcpiGbl_DbMethodInfo
.InfoGate
= InfoGate
;
782 /* Init arguments to be passed to method */
784 AcpiGbl_DbMethodInfo
.InitArgs
= 1;
785 AcpiGbl_DbMethodInfo
.Args
= AcpiGbl_DbMethodInfo
.Arguments
;
786 AcpiGbl_DbMethodInfo
.Arguments
[0] = AcpiGbl_DbMethodInfo
.NumThreadsStr
;
787 AcpiGbl_DbMethodInfo
.Arguments
[1] = AcpiGbl_DbMethodInfo
.IdOfThreadStr
;
788 AcpiGbl_DbMethodInfo
.Arguments
[2] = AcpiGbl_DbMethodInfo
.IndexOfThreadStr
;
789 AcpiGbl_DbMethodInfo
.Arguments
[3] = NULL
;
791 AcpiGbl_DbMethodInfo
.Types
= AcpiGbl_DbMethodInfo
.ArgTypes
;
792 AcpiGbl_DbMethodInfo
.ArgTypes
[0] = ACPI_TYPE_INTEGER
;
793 AcpiGbl_DbMethodInfo
.ArgTypes
[1] = ACPI_TYPE_INTEGER
;
794 AcpiGbl_DbMethodInfo
.ArgTypes
[2] = ACPI_TYPE_INTEGER
;
796 AcpiDbUint32ToHexString (NumThreads
, AcpiGbl_DbMethodInfo
.NumThreadsStr
);
798 Status
= AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo
);
799 if (ACPI_FAILURE (Status
))
804 /* Get the NS node, determines existence also */
806 Status
= AcpiGetHandle (NULL
, AcpiGbl_DbMethodInfo
.Pathname
,
807 &AcpiGbl_DbMethodInfo
.Method
);
808 if (ACPI_FAILURE (Status
))
810 AcpiOsPrintf ("%s Could not get handle for %s\n",
811 AcpiFormatException (Status
), AcpiGbl_DbMethodInfo
.Pathname
);
815 /* Create the threads */
817 AcpiOsPrintf ("Creating %X threads to execute %X times each\n",
818 NumThreads
, NumLoops
);
820 for (i
= 0; i
< (NumThreads
); i
++)
822 Status
= AcpiOsExecute (OSL_DEBUGGER_EXEC_THREAD
, AcpiDbMethodThread
,
823 &AcpiGbl_DbMethodInfo
);
824 if (ACPI_FAILURE (Status
))
830 /* Wait for all threads to complete */
832 (void) AcpiOsWaitSemaphore (MainThreadGate
, 1, ACPI_WAIT_FOREVER
);
834 AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT
);
835 AcpiOsPrintf ("All threads (%X) have completed\n", NumThreads
);
836 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT
);
840 /* Cleanup and exit */
842 (void) AcpiOsDeleteSemaphore (MainThreadGate
);
843 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate
);
844 (void) AcpiOsDeleteSemaphore (InfoGate
);
846 AcpiOsFree (AcpiGbl_DbMethodInfo
.Threads
);
847 AcpiGbl_DbMethodInfo
.Threads
= NULL
;
850 #endif /* ACPI_DEBUGGER */