xref: /netbsd-src/sys/external/bsd/acpica/dist/debugger/dbexec.c (revision 2e2322c9c07009df921d11b1268f8506affbb8ba)
1 /*******************************************************************************
2  *
3  * Module Name: dbexec - debugger control method execution
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 #include "acpi.h"
45 #include "accommon.h"
46 #include "acdebug.h"
47 #include "acnamesp.h"
48 
49 
50 #define _COMPONENT          ACPI_CA_DEBUGGER
51         ACPI_MODULE_NAME    ("dbexec")
52 
53 
54 static ACPI_DB_METHOD_INFO          AcpiGbl_DbMethodInfo;
55 
56 /* Local prototypes */
57 
58 static ACPI_STATUS
59 AcpiDbExecuteMethod (
60     ACPI_DB_METHOD_INFO     *Info,
61     ACPI_BUFFER             *ReturnObj);
62 
63 static ACPI_STATUS
64 AcpiDbExecuteSetup (
65     ACPI_DB_METHOD_INFO     *Info);
66 
67 static UINT32
68 AcpiDbGetOutstandingAllocations (
69     void);
70 
71 static void ACPI_SYSTEM_XFACE
72 AcpiDbMethodThread (
73     void                    *Context);
74 
75 static ACPI_STATUS
76 AcpiDbExecutionWalk (
77     ACPI_HANDLE             ObjHandle,
78     UINT32                  NestingLevel,
79     void                    *Context,
80     void                    **ReturnValue);
81 
82 
83 /*******************************************************************************
84  *
85  * FUNCTION:    AcpiDbDeleteObjects
86  *
87  * PARAMETERS:  Count               - Count of objects in the list
88  *              Objects             - Array of ACPI_OBJECTs to be deleted
89  *
90  * RETURN:      None
91  *
92  * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
93  *              packages via recursion.
94  *
95  ******************************************************************************/
96 
97 void
98 AcpiDbDeleteObjects (
99     UINT32                  Count,
100     ACPI_OBJECT             *Objects)
101 {
102     UINT32                  i;
103 
104 
105     for (i = 0; i < Count; i++)
106     {
107         switch (Objects[i].Type)
108         {
109         case ACPI_TYPE_BUFFER:
110 
111             ACPI_FREE (Objects[i].Buffer.Pointer);
112             break;
113 
114         case ACPI_TYPE_PACKAGE:
115 
116             /* Recursive call to delete package elements */
117 
118             AcpiDbDeleteObjects (Objects[i].Package.Count,
119                 Objects[i].Package.Elements);
120 
121             /* Free the elements array */
122 
123             ACPI_FREE (Objects[i].Package.Elements);
124             break;
125 
126         default:
127 
128             break;
129         }
130     }
131 }
132 
133 
134 /*******************************************************************************
135  *
136  * FUNCTION:    AcpiDbExecuteMethod
137  *
138  * PARAMETERS:  Info            - Valid info segment
139  *              ReturnObj       - Where to put return object
140  *
141  * RETURN:      Status
142  *
143  * DESCRIPTION: Execute a control method.
144  *
145  ******************************************************************************/
146 
147 static ACPI_STATUS
148 AcpiDbExecuteMethod (
149     ACPI_DB_METHOD_INFO     *Info,
150     ACPI_BUFFER             *ReturnObj)
151 {
152     ACPI_STATUS             Status;
153     ACPI_OBJECT_LIST        ParamObjects;
154     ACPI_OBJECT             Params[ACPI_DEBUGGER_MAX_ARGS + 1];
155     UINT32                  i;
156 
157 
158     ACPI_FUNCTION_TRACE (DbExecuteMethod);
159 
160 
161     if (AcpiGbl_DbOutputToFile && !AcpiDbgLevel)
162     {
163         AcpiOsPrintf ("Warning: debug output is not enabled!\n");
164     }
165 
166     ParamObjects.Count = 0;
167     ParamObjects.Pointer = NULL;
168 
169     /* Pass through any command-line arguments */
170 
171     if (Info->Args && Info->Args[0])
172     {
173         /* Get arguments passed on the command line */
174 
175         for (i = 0; (Info->Args[i] && *(Info->Args[i])); i++)
176         {
177             /* Convert input string (token) to an actual ACPI_OBJECT */
178 
179             Status = AcpiDbConvertToObject (Info->Types[i],
180                 Info->Args[i], &Params[i]);
181             if (ACPI_FAILURE (Status))
182             {
183                 ACPI_EXCEPTION ((AE_INFO, Status,
184                     "While parsing method arguments"));
185                 goto Cleanup;
186             }
187         }
188 
189         ParamObjects.Count = i;
190         ParamObjects.Pointer = Params;
191     }
192 
193     /* Prepare for a return object of arbitrary size */
194 
195     ReturnObj->Pointer = AcpiGbl_DbBuffer;
196     ReturnObj->Length  = ACPI_DEBUG_BUFFER_SIZE;
197 
198     /* Do the actual method execution */
199 
200     AcpiGbl_MethodExecuting = TRUE;
201     Status = AcpiEvaluateObject (NULL, Info->Pathname,
202         &ParamObjects, ReturnObj);
203 
204     AcpiGbl_CmSingleStep = FALSE;
205     AcpiGbl_MethodExecuting = FALSE;
206 
207     if (ACPI_FAILURE (Status))
208     {
209         ACPI_EXCEPTION ((AE_INFO, Status,
210             "while executing %s from debugger", Info->Pathname));
211 
212         if (Status == AE_BUFFER_OVERFLOW)
213         {
214             ACPI_ERROR ((AE_INFO,
215                 "Possible overflow of internal debugger "
216                 "buffer (size 0x%X needed 0x%X)",
217                 ACPI_DEBUG_BUFFER_SIZE, (UINT32) ReturnObj->Length));
218         }
219     }
220 
221 Cleanup:
222     AcpiDbDeleteObjects (ParamObjects.Count, Params);
223     return_ACPI_STATUS (Status);
224 }
225 
226 
227 /*******************************************************************************
228  *
229  * FUNCTION:    AcpiDbExecuteSetup
230  *
231  * PARAMETERS:  Info            - Valid method info
232  *
233  * RETURN:      None
234  *
235  * DESCRIPTION: Setup info segment prior to method execution
236  *
237  ******************************************************************************/
238 
239 static ACPI_STATUS
240 AcpiDbExecuteSetup (
241     ACPI_DB_METHOD_INFO     *Info)
242 {
243     ACPI_STATUS             Status;
244 
245 
246     ACPI_FUNCTION_NAME (DbExecuteSetup);
247 
248 
249     /* Catenate the current scope to the supplied name */
250 
251     Info->Pathname[0] = 0;
252     if ((Info->Name[0] != '\\') &&
253         (Info->Name[0] != '/'))
254     {
255         if (AcpiUtSafeStrcat (Info->Pathname, sizeof (Info->Pathname),
256             AcpiGbl_DbScopeBuf))
257         {
258             Status = AE_BUFFER_OVERFLOW;
259             goto ErrorExit;
260         }
261     }
262 
263     if (AcpiUtSafeStrcat (Info->Pathname, sizeof (Info->Pathname),
264         Info->Name))
265     {
266         Status = AE_BUFFER_OVERFLOW;
267         goto ErrorExit;
268     }
269 
270     AcpiDbPrepNamestring (Info->Pathname);
271 
272     AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
273     AcpiOsPrintf ("Evaluating %s\n", Info->Pathname);
274 
275     if (Info->Flags & EX_SINGLE_STEP)
276     {
277         AcpiGbl_CmSingleStep = TRUE;
278         AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
279     }
280 
281     else
282     {
283         /* No single step, allow redirection to a file */
284 
285         AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT);
286     }
287 
288     return (AE_OK);
289 
290 ErrorExit:
291 
292     ACPI_EXCEPTION ((AE_INFO, Status, "During setup for method execution"));
293     return (Status);
294 }
295 
296 
297 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
298 UINT32
299 AcpiDbGetCacheInfo (
300     ACPI_MEMORY_LIST        *Cache)
301 {
302 
303     return (Cache->TotalAllocated - Cache->TotalFreed - Cache->CurrentDepth);
304 }
305 #endif
306 
307 /*******************************************************************************
308  *
309  * FUNCTION:    AcpiDbGetOutstandingAllocations
310  *
311  * PARAMETERS:  None
312  *
313  * RETURN:      Current global allocation count minus cache entries
314  *
315  * DESCRIPTION: Determine the current number of "outstanding" allocations --
316  *              those allocations that have not been freed and also are not
317  *              in one of the various object caches.
318  *
319  ******************************************************************************/
320 
321 #ifdef ACPI_DEBUG_OUTPUT
322 static UINT32
323 AcpiDbGetOutstandingAllocations (
324     void)
325 {
326     UINT32                  Outstanding = 0;
327 
328 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
329 
330     Outstanding += AcpiDbGetCacheInfo (AcpiGbl_StateCache);
331     Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeCache);
332     Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeExtCache);
333     Outstanding += AcpiDbGetCacheInfo (AcpiGbl_OperandCache);
334 #endif
335 
336     return (Outstanding);
337 }
338 #endif
339 
340 
341 /*******************************************************************************
342  *
343  * FUNCTION:    AcpiDbExecutionWalk
344  *
345  * PARAMETERS:  WALK_CALLBACK
346  *
347  * RETURN:      Status
348  *
349  * DESCRIPTION: Execute a control method. Name is relative to the current
350  *              scope.
351  *
352  ******************************************************************************/
353 
354 static ACPI_STATUS
355 AcpiDbExecutionWalk (
356     ACPI_HANDLE             ObjHandle,
357     UINT32                  NestingLevel,
358     void                    *Context,
359     void                    **ReturnValue)
360 {
361     ACPI_OPERAND_OBJECT     *ObjDesc;
362     ACPI_NAMESPACE_NODE     *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
363     ACPI_BUFFER             ReturnObj;
364     ACPI_STATUS             Status;
365 
366 
367     ObjDesc = AcpiNsGetAttachedObject (Node);
368     if (ObjDesc->Method.ParamCount)
369     {
370         return (AE_OK);
371     }
372 
373     ReturnObj.Pointer = NULL;
374     ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
375 
376     AcpiNsPrintNodePathname (Node, "Evaluating");
377 
378     /* Do the actual method execution */
379 
380     AcpiOsPrintf ("\n");
381     AcpiGbl_MethodExecuting = TRUE;
382 
383     Status = AcpiEvaluateObject (Node, NULL, NULL, &ReturnObj);
384 
385     AcpiOsPrintf ("Evaluation of [%4.4s] returned %s\n",
386         AcpiUtGetNodeName (Node),
387         AcpiFormatException (Status));
388 
389     AcpiGbl_MethodExecuting = FALSE;
390     return (AE_OK);
391 }
392 
393 
394 /*******************************************************************************
395  *
396  * FUNCTION:    AcpiDbExecute
397  *
398  * PARAMETERS:  Name                - Name of method to execute
399  *              Args                - Parameters to the method
400  *              Types               -
401  *              Flags               - single step/no single step
402  *
403  * RETURN:      None
404  *
405  * DESCRIPTION: Execute a control method. Name is relative to the current
406  *              scope.
407  *
408  ******************************************************************************/
409 
410 void
411 AcpiDbExecute (
412     char                    *Name,
413     char                    **Args,
414     ACPI_OBJECT_TYPE        *Types,
415     UINT32                  Flags)
416 {
417     ACPI_STATUS             Status;
418     ACPI_BUFFER             ReturnObj;
419     char                    *NameString;
420 
421 #ifdef ACPI_DEBUG_OUTPUT
422     UINT32                  PreviousAllocations;
423     UINT32                  Allocations;
424 #endif
425 
426 
427     /*
428      * Allow one execution to be performed by debugger or single step
429      * execution will be dead locked by the interpreter mutexes.
430      */
431     if (AcpiGbl_MethodExecuting)
432     {
433         AcpiOsPrintf ("Only one debugger execution is allowed.\n");
434         return;
435     }
436 
437 #ifdef ACPI_DEBUG_OUTPUT
438     /* Memory allocation tracking */
439 
440     PreviousAllocations = AcpiDbGetOutstandingAllocations ();
441 #endif
442 
443     if (*Name == '*')
444     {
445         (void) AcpiWalkNamespace (ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
446             ACPI_UINT32_MAX, AcpiDbExecutionWalk, NULL, NULL, NULL);
447         return;
448     }
449 
450     NameString = ACPI_ALLOCATE (strlen (Name) + 1);
451     if (!NameString)
452     {
453         return;
454     }
455 
456     memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
457     strcpy (NameString, Name);
458     AcpiUtStrupr (NameString);
459 
460     /* Subcommand to Execute all predefined names in the namespace */
461 
462     if (!strncmp (NameString, "PREDEF", 6))
463     {
464         AcpiDbEvaluatePredefinedNames ();
465         ACPI_FREE (NameString);
466         return;
467     }
468 
469     AcpiGbl_DbMethodInfo.Name = NameString;
470     AcpiGbl_DbMethodInfo.Args = Args;
471     AcpiGbl_DbMethodInfo.Types = Types;
472     AcpiGbl_DbMethodInfo.Flags = Flags;
473 
474     ReturnObj.Pointer = NULL;
475     ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
476 
477     Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
478     if (ACPI_FAILURE (Status))
479     {
480         ACPI_FREE (NameString);
481         return;
482     }
483 
484     /* Get the NS node, determines existence also */
485 
486     Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
487         &AcpiGbl_DbMethodInfo.Method);
488     if (ACPI_SUCCESS (Status))
489     {
490         Status = AcpiDbExecuteMethod (&AcpiGbl_DbMethodInfo,
491             &ReturnObj);
492     }
493     ACPI_FREE (NameString);
494 
495     /*
496      * Allow any handlers in separate threads to complete.
497      * (Such as Notify handlers invoked from AML executed above).
498      */
499     AcpiOsSleep ((UINT64) 10);
500 
501 #ifdef ACPI_DEBUG_OUTPUT
502 
503     /* Memory allocation tracking */
504 
505     Allocations = AcpiDbGetOutstandingAllocations () - PreviousAllocations;
506 
507     AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
508 
509     if (Allocations > 0)
510     {
511         AcpiOsPrintf (
512             "0x%X Outstanding allocations after evaluation of %s\n",
513             Allocations, AcpiGbl_DbMethodInfo.Pathname);
514     }
515 #endif
516 
517     if (ACPI_FAILURE (Status))
518     {
519         AcpiOsPrintf ("Evaluation of %s failed with status %s\n",
520             AcpiGbl_DbMethodInfo.Pathname,
521             AcpiFormatException (Status));
522     }
523     else
524     {
525         /* Display a return object, if any */
526 
527         if (ReturnObj.Length)
528         {
529             AcpiOsPrintf (
530                 "Evaluation of %s returned object %p, "
531                 "external buffer length %X\n",
532                 AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer,
533                 (UINT32) ReturnObj.Length);
534 
535             AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
536 
537             /* Dump a _PLD buffer if present */
538 
539             if (ACPI_COMPARE_NAME ((ACPI_CAST_PTR (ACPI_NAMESPACE_NODE,
540                 AcpiGbl_DbMethodInfo.Method)->Name.Ascii),
541                 METHOD_NAME__PLD))
542             {
543                 AcpiDbDumpPldBuffer (ReturnObj.Pointer);
544             }
545         }
546         else
547         {
548             AcpiOsPrintf ("No object was returned from evaluation of %s\n",
549                 AcpiGbl_DbMethodInfo.Pathname);
550         }
551     }
552 
553     AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
554 }
555 
556 
557 /*******************************************************************************
558  *
559  * FUNCTION:    AcpiDbMethodThread
560  *
561  * PARAMETERS:  Context             - Execution info segment
562  *
563  * RETURN:      None
564  *
565  * DESCRIPTION: Debugger execute thread. Waits for a command line, then
566  *              simply dispatches it.
567  *
568  ******************************************************************************/
569 
570 static void ACPI_SYSTEM_XFACE
571 AcpiDbMethodThread (
572     void                    *Context)
573 {
574     ACPI_STATUS             Status;
575     ACPI_DB_METHOD_INFO     *Info = Context;
576     ACPI_DB_METHOD_INFO     LocalInfo;
577     UINT32                  i;
578     UINT8                   Allow;
579     ACPI_BUFFER             ReturnObj;
580 
581 
582     /*
583      * AcpiGbl_DbMethodInfo.Arguments will be passed as method arguments.
584      * Prevent AcpiGbl_DbMethodInfo from being modified by multiple threads
585      * concurrently.
586      *
587      * Note: The arguments we are passing are used by the ASL test suite
588      * (aslts). Do not change them without updating the tests.
589      */
590     (void) AcpiOsWaitSemaphore (Info->InfoGate, 1, ACPI_WAIT_FOREVER);
591 
592     if (Info->InitArgs)
593     {
594         AcpiDbUint32ToHexString (Info->NumCreated,
595             Info->IndexOfThreadStr);
596         AcpiDbUint32ToHexString ((UINT32) AcpiOsGetThreadId (),
597             Info->IdOfThreadStr);
598     }
599 
600     if (Info->Threads && (Info->NumCreated < Info->NumThreads))
601     {
602         Info->Threads[Info->NumCreated++] = AcpiOsGetThreadId();
603     }
604 
605     LocalInfo = *Info;
606     LocalInfo.Args = LocalInfo.Arguments;
607     LocalInfo.Arguments[0] = LocalInfo.NumThreadsStr;
608     LocalInfo.Arguments[1] = LocalInfo.IdOfThreadStr;
609     LocalInfo.Arguments[2] = LocalInfo.IndexOfThreadStr;
610     LocalInfo.Arguments[3] = NULL;
611 
612     LocalInfo.Types = LocalInfo.ArgTypes;
613 
614     (void) AcpiOsSignalSemaphore (Info->InfoGate, 1);
615 
616     for (i = 0; i < Info->NumLoops; i++)
617     {
618         Status = AcpiDbExecuteMethod (&LocalInfo, &ReturnObj);
619         if (ACPI_FAILURE (Status))
620         {
621             AcpiOsPrintf ("%s During evaluation of %s at iteration %X\n",
622                 AcpiFormatException (Status), Info->Pathname, i);
623             if (Status == AE_ABORT_METHOD)
624             {
625                 break;
626             }
627         }
628 
629 #if 0
630         if ((i % 100) == 0)
631         {
632             AcpiOsPrintf ("%u loops, Thread 0x%x\n",
633                 i, AcpiOsGetThreadId ());
634         }
635 
636         if (ReturnObj.Length)
637         {
638             AcpiOsPrintf ("Evaluation of %s returned object %p Buflen %X\n",
639                 Info->Pathname, ReturnObj.Pointer,
640                 (UINT32) ReturnObj.Length);
641             AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
642         }
643 #endif
644     }
645 
646     /* Signal our completion */
647 
648     Allow = 0;
649     (void) AcpiOsWaitSemaphore (Info->ThreadCompleteGate,
650         1, ACPI_WAIT_FOREVER);
651     Info->NumCompleted++;
652 
653     if (Info->NumCompleted == Info->NumThreads)
654     {
655         /* Do signal for main thread once only */
656         Allow = 1;
657     }
658 
659     (void) AcpiOsSignalSemaphore (Info->ThreadCompleteGate, 1);
660 
661     if (Allow)
662     {
663         Status = AcpiOsSignalSemaphore (Info->MainThreadGate, 1);
664         if (ACPI_FAILURE (Status))
665         {
666             AcpiOsPrintf (
667                 "Could not signal debugger thread sync semaphore, %s\n",
668                 AcpiFormatException (Status));
669         }
670     }
671 }
672 
673 
674 /*******************************************************************************
675  *
676  * FUNCTION:    AcpiDbCreateExecutionThreads
677  *
678  * PARAMETERS:  NumThreadsArg           - Number of threads to create
679  *              NumLoopsArg             - Loop count for the thread(s)
680  *              MethodNameArg           - Control method to execute
681  *
682  * RETURN:      None
683  *
684  * DESCRIPTION: Create threads to execute method(s)
685  *
686  ******************************************************************************/
687 
688 void
689 AcpiDbCreateExecutionThreads (
690     char                    *NumThreadsArg,
691     char                    *NumLoopsArg,
692     char                    *MethodNameArg)
693 {
694     ACPI_STATUS             Status;
695     UINT32                  NumThreads;
696     UINT32                  NumLoops;
697     UINT32                  i;
698     UINT32                  Size;
699     ACPI_MUTEX              MainThreadGate;
700     ACPI_MUTEX              ThreadCompleteGate;
701     ACPI_MUTEX              InfoGate;
702 
703 
704     /* Get the arguments */
705 
706     NumThreads = strtoul (NumThreadsArg, NULL, 0);
707     NumLoops = strtoul (NumLoopsArg, NULL, 0);
708 
709     if (!NumThreads || !NumLoops)
710     {
711         AcpiOsPrintf ("Bad argument: Threads %X, Loops %X\n",
712             NumThreads, NumLoops);
713         return;
714     }
715 
716     /*
717      * Create the semaphore for synchronization of
718      * the created threads with the main thread.
719      */
720     Status = AcpiOsCreateSemaphore (1, 0, &MainThreadGate);
721     if (ACPI_FAILURE (Status))
722     {
723         AcpiOsPrintf ("Could not create semaphore for "
724             "synchronization with the main thread, %s\n",
725             AcpiFormatException (Status));
726         return;
727     }
728 
729     /*
730      * Create the semaphore for synchronization
731      * between the created threads.
732      */
733     Status = AcpiOsCreateSemaphore (1, 1, &ThreadCompleteGate);
734     if (ACPI_FAILURE (Status))
735     {
736         AcpiOsPrintf ("Could not create semaphore for "
737             "synchronization between the created threads, %s\n",
738             AcpiFormatException (Status));
739 
740         (void) AcpiOsDeleteSemaphore (MainThreadGate);
741         return;
742     }
743 
744     Status = AcpiOsCreateSemaphore (1, 1, &InfoGate);
745     if (ACPI_FAILURE (Status))
746     {
747         AcpiOsPrintf ("Could not create semaphore for "
748             "synchronization of AcpiGbl_DbMethodInfo, %s\n",
749             AcpiFormatException (Status));
750 
751         (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
752         (void) AcpiOsDeleteSemaphore (MainThreadGate);
753         return;
754     }
755 
756     memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
757 
758     /* Array to store IDs of threads */
759 
760     AcpiGbl_DbMethodInfo.NumThreads = NumThreads;
761     Size = sizeof (ACPI_THREAD_ID) * AcpiGbl_DbMethodInfo.NumThreads;
762 
763     AcpiGbl_DbMethodInfo.Threads = AcpiOsAllocate (Size);
764     if (AcpiGbl_DbMethodInfo.Threads == NULL)
765     {
766         AcpiOsPrintf ("No memory for thread IDs array\n");
767         (void) AcpiOsDeleteSemaphore (MainThreadGate);
768         (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
769         (void) AcpiOsDeleteSemaphore (InfoGate);
770         return;
771     }
772     memset (AcpiGbl_DbMethodInfo.Threads, 0, Size);
773 
774     /* Setup the context to be passed to each thread */
775 
776     AcpiGbl_DbMethodInfo.Name = MethodNameArg;
777     AcpiGbl_DbMethodInfo.Flags = 0;
778     AcpiGbl_DbMethodInfo.NumLoops = NumLoops;
779     AcpiGbl_DbMethodInfo.MainThreadGate = MainThreadGate;
780     AcpiGbl_DbMethodInfo.ThreadCompleteGate = ThreadCompleteGate;
781     AcpiGbl_DbMethodInfo.InfoGate = InfoGate;
782 
783     /* Init arguments to be passed to method */
784 
785     AcpiGbl_DbMethodInfo.InitArgs = 1;
786     AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments;
787     AcpiGbl_DbMethodInfo.Arguments[0] = AcpiGbl_DbMethodInfo.NumThreadsStr;
788     AcpiGbl_DbMethodInfo.Arguments[1] = AcpiGbl_DbMethodInfo.IdOfThreadStr;
789     AcpiGbl_DbMethodInfo.Arguments[2] = AcpiGbl_DbMethodInfo.IndexOfThreadStr;
790     AcpiGbl_DbMethodInfo.Arguments[3] = NULL;
791 
792     AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes;
793     AcpiGbl_DbMethodInfo.ArgTypes[0] = ACPI_TYPE_INTEGER;
794     AcpiGbl_DbMethodInfo.ArgTypes[1] = ACPI_TYPE_INTEGER;
795     AcpiGbl_DbMethodInfo.ArgTypes[2] = ACPI_TYPE_INTEGER;
796 
797     AcpiDbUint32ToHexString (NumThreads, AcpiGbl_DbMethodInfo.NumThreadsStr);
798 
799     Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
800     if (ACPI_FAILURE (Status))
801     {
802         goto CleanupAndExit;
803     }
804 
805     /* Get the NS node, determines existence also */
806 
807     Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
808         &AcpiGbl_DbMethodInfo.Method);
809     if (ACPI_FAILURE (Status))
810     {
811         AcpiOsPrintf ("%s Could not get handle for %s\n",
812             AcpiFormatException (Status), AcpiGbl_DbMethodInfo.Pathname);
813         goto CleanupAndExit;
814     }
815 
816     /* Create the threads */
817 
818     AcpiOsPrintf ("Creating %X threads to execute %X times each\n",
819         NumThreads, NumLoops);
820 
821     for (i = 0; i < (NumThreads); i++)
822     {
823         Status = AcpiOsExecute (OSL_DEBUGGER_EXEC_THREAD, AcpiDbMethodThread,
824             &AcpiGbl_DbMethodInfo);
825         if (ACPI_FAILURE (Status))
826         {
827             break;
828         }
829     }
830 
831     /* Wait for all threads to complete */
832 
833     (void) AcpiOsWaitSemaphore (MainThreadGate, 1, ACPI_WAIT_FOREVER);
834 
835     AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
836     AcpiOsPrintf ("All threads (%X) have completed\n", NumThreads);
837     AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
838 
839 CleanupAndExit:
840 
841     /* Cleanup and exit */
842 
843     (void) AcpiOsDeleteSemaphore (MainThreadGate);
844     (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
845     (void) AcpiOsDeleteSemaphore (InfoGate);
846 
847     AcpiOsFree (AcpiGbl_DbMethodInfo.Threads);
848     AcpiGbl_DbMethodInfo.Threads = NULL;
849 }
850