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