]>
Commit | Line | Data |
---|---|---|
99575102 LZ |
1 | /******************************************************************************* |
2 | * | |
3 | * Module Name: dbexec - debugger control method execution | |
4 | * | |
5 | ******************************************************************************/ | |
6 | ||
7 | /* | |
7735ca0e | 8 | * Copyright (C) 2000 - 2017, Intel Corp. |
99575102 LZ |
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/acpi.h> | |
45 | #include "accommon.h" | |
46 | #include "acdebug.h" | |
47 | #include "acnamesp.h" | |
48 | ||
49 | #define _COMPONENT ACPI_CA_DEBUGGER | |
50 | ACPI_MODULE_NAME("dbexec") | |
51 | ||
52 | static struct acpi_db_method_info acpi_gbl_db_method_info; | |
53 | ||
54 | /* Local prototypes */ | |
55 | ||
56 | static acpi_status | |
57 | acpi_db_execute_method(struct acpi_db_method_info *info, | |
58 | struct acpi_buffer *return_obj); | |
59 | ||
60 | static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info); | |
61 | ||
62 | static u32 acpi_db_get_outstanding_allocations(void); | |
63 | ||
64 | static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context); | |
65 | ||
66 | static acpi_status | |
67 | acpi_db_execution_walk(acpi_handle obj_handle, | |
68 | u32 nesting_level, void *context, void **return_value); | |
69 | ||
70 | /******************************************************************************* | |
71 | * | |
72 | * FUNCTION: acpi_db_delete_objects | |
73 | * | |
74 | * PARAMETERS: count - Count of objects in the list | |
75 | * objects - Array of ACPI_OBJECTs to be deleted | |
76 | * | |
77 | * RETURN: None | |
78 | * | |
79 | * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested | |
80 | * packages via recursion. | |
81 | * | |
82 | ******************************************************************************/ | |
83 | ||
84 | void acpi_db_delete_objects(u32 count, union acpi_object *objects) | |
85 | { | |
86 | u32 i; | |
87 | ||
88 | for (i = 0; i < count; i++) { | |
89 | switch (objects[i].type) { | |
90 | case ACPI_TYPE_BUFFER: | |
91 | ||
92 | ACPI_FREE(objects[i].buffer.pointer); | |
93 | break; | |
94 | ||
95 | case ACPI_TYPE_PACKAGE: | |
96 | ||
97 | /* Recursive call to delete package elements */ | |
98 | ||
99 | acpi_db_delete_objects(objects[i].package.count, | |
100 | objects[i].package.elements); | |
101 | ||
102 | /* Free the elements array */ | |
103 | ||
104 | ACPI_FREE(objects[i].package.elements); | |
105 | break; | |
106 | ||
107 | default: | |
108 | ||
109 | break; | |
110 | } | |
111 | } | |
112 | } | |
113 | ||
114 | /******************************************************************************* | |
115 | * | |
116 | * FUNCTION: acpi_db_execute_method | |
117 | * | |
118 | * PARAMETERS: info - Valid info segment | |
119 | * return_obj - Where to put return object | |
120 | * | |
121 | * RETURN: Status | |
122 | * | |
123 | * DESCRIPTION: Execute a control method. | |
124 | * | |
125 | ******************************************************************************/ | |
126 | ||
127 | static acpi_status | |
128 | acpi_db_execute_method(struct acpi_db_method_info *info, | |
129 | struct acpi_buffer *return_obj) | |
130 | { | |
131 | acpi_status status; | |
132 | struct acpi_object_list param_objects; | |
133 | union acpi_object params[ACPI_DEBUGGER_MAX_ARGS + 1]; | |
134 | u32 i; | |
135 | ||
136 | ACPI_FUNCTION_TRACE(db_execute_method); | |
137 | ||
138 | if (acpi_gbl_db_output_to_file && !acpi_dbg_level) { | |
139 | acpi_os_printf("Warning: debug output is not enabled!\n"); | |
140 | } | |
141 | ||
142 | param_objects.count = 0; | |
143 | param_objects.pointer = NULL; | |
144 | ||
145 | /* Pass through any command-line arguments */ | |
146 | ||
147 | if (info->args && info->args[0]) { | |
148 | ||
149 | /* Get arguments passed on the command line */ | |
150 | ||
151 | for (i = 0; (info->args[i] && *(info->args[i])); i++) { | |
152 | ||
153 | /* Convert input string (token) to an actual union acpi_object */ | |
154 | ||
155 | status = acpi_db_convert_to_object(info->types[i], | |
156 | info->args[i], | |
157 | ¶ms[i]); | |
158 | if (ACPI_FAILURE(status)) { | |
159 | ACPI_EXCEPTION((AE_INFO, status, | |
160 | "While parsing method arguments")); | |
161 | goto cleanup; | |
162 | } | |
163 | } | |
164 | ||
165 | param_objects.count = i; | |
166 | param_objects.pointer = params; | |
167 | } | |
168 | ||
169 | /* Prepare for a return object of arbitrary size */ | |
170 | ||
171 | return_obj->pointer = acpi_gbl_db_buffer; | |
172 | return_obj->length = ACPI_DEBUG_BUFFER_SIZE; | |
173 | ||
174 | /* Do the actual method execution */ | |
175 | ||
176 | acpi_gbl_method_executing = TRUE; | |
177 | status = acpi_evaluate_object(NULL, info->pathname, | |
178 | ¶m_objects, return_obj); | |
179 | ||
180 | acpi_gbl_cm_single_step = FALSE; | |
181 | acpi_gbl_method_executing = FALSE; | |
182 | ||
183 | if (ACPI_FAILURE(status)) { | |
fd13aaa8 BM |
184 | if ((status == AE_ABORT_METHOD) || acpi_gbl_abort_method) { |
185 | ||
186 | /* Clear the abort and fall back to the debugger prompt */ | |
187 | ||
188 | ACPI_EXCEPTION((AE_INFO, status, | |
189 | "Aborting top-level method")); | |
190 | ||
191 | acpi_gbl_abort_method = FALSE; | |
192 | status = AE_OK; | |
193 | goto cleanup; | |
194 | } | |
195 | ||
99575102 LZ |
196 | ACPI_EXCEPTION((AE_INFO, status, |
197 | "while executing %s from debugger", | |
198 | info->pathname)); | |
199 | ||
200 | if (status == AE_BUFFER_OVERFLOW) { | |
201 | ACPI_ERROR((AE_INFO, | |
202 | "Possible overflow of internal debugger " | |
203 | "buffer (size 0x%X needed 0x%X)", | |
204 | ACPI_DEBUG_BUFFER_SIZE, | |
205 | (u32)return_obj->length)); | |
206 | } | |
207 | } | |
208 | ||
209 | cleanup: | |
210 | acpi_db_delete_objects(param_objects.count, params); | |
211 | return_ACPI_STATUS(status); | |
212 | } | |
213 | ||
214 | /******************************************************************************* | |
215 | * | |
216 | * FUNCTION: acpi_db_execute_setup | |
217 | * | |
218 | * PARAMETERS: info - Valid method info | |
219 | * | |
220 | * RETURN: None | |
221 | * | |
222 | * DESCRIPTION: Setup info segment prior to method execution | |
223 | * | |
224 | ******************************************************************************/ | |
225 | ||
226 | static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info) | |
227 | { | |
228 | acpi_status status; | |
229 | ||
230 | ACPI_FUNCTION_NAME(db_execute_setup); | |
231 | ||
232 | /* Catenate the current scope to the supplied name */ | |
233 | ||
234 | info->pathname[0] = 0; | |
235 | if ((info->name[0] != '\\') && (info->name[0] != '/')) { | |
236 | if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname), | |
237 | acpi_gbl_db_scope_buf)) { | |
238 | status = AE_BUFFER_OVERFLOW; | |
239 | goto error_exit; | |
240 | } | |
241 | } | |
242 | ||
243 | if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname), | |
244 | info->name)) { | |
245 | status = AE_BUFFER_OVERFLOW; | |
246 | goto error_exit; | |
247 | } | |
248 | ||
249 | acpi_db_prep_namestring(info->pathname); | |
250 | ||
251 | acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); | |
252 | acpi_os_printf("Evaluating %s\n", info->pathname); | |
253 | ||
254 | if (info->flags & EX_SINGLE_STEP) { | |
255 | acpi_gbl_cm_single_step = TRUE; | |
256 | acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); | |
257 | } | |
258 | ||
259 | else { | |
260 | /* No single step, allow redirection to a file */ | |
261 | ||
262 | acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); | |
263 | } | |
264 | ||
265 | return (AE_OK); | |
266 | ||
267 | error_exit: | |
268 | ||
269 | ACPI_EXCEPTION((AE_INFO, status, "During setup for method execution")); | |
270 | return (status); | |
271 | } | |
272 | ||
273 | #ifdef ACPI_DBG_TRACK_ALLOCATIONS | |
274 | u32 acpi_db_get_cache_info(struct acpi_memory_list *cache) | |
275 | { | |
276 | ||
277 | return (cache->total_allocated - cache->total_freed - | |
278 | cache->current_depth); | |
279 | } | |
280 | #endif | |
281 | ||
282 | /******************************************************************************* | |
283 | * | |
284 | * FUNCTION: acpi_db_get_outstanding_allocations | |
285 | * | |
286 | * PARAMETERS: None | |
287 | * | |
288 | * RETURN: Current global allocation count minus cache entries | |
289 | * | |
290 | * DESCRIPTION: Determine the current number of "outstanding" allocations -- | |
291 | * those allocations that have not been freed and also are not | |
292 | * in one of the various object caches. | |
293 | * | |
294 | ******************************************************************************/ | |
295 | ||
296 | static u32 acpi_db_get_outstanding_allocations(void) | |
297 | { | |
298 | u32 outstanding = 0; | |
299 | ||
300 | #ifdef ACPI_DBG_TRACK_ALLOCATIONS | |
301 | ||
302 | outstanding += acpi_db_get_cache_info(acpi_gbl_state_cache); | |
303 | outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_cache); | |
304 | outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_ext_cache); | |
305 | outstanding += acpi_db_get_cache_info(acpi_gbl_operand_cache); | |
306 | #endif | |
307 | ||
308 | return (outstanding); | |
309 | } | |
310 | ||
311 | /******************************************************************************* | |
312 | * | |
313 | * FUNCTION: acpi_db_execution_walk | |
314 | * | |
315 | * PARAMETERS: WALK_CALLBACK | |
316 | * | |
317 | * RETURN: Status | |
318 | * | |
319 | * DESCRIPTION: Execute a control method. Name is relative to the current | |
320 | * scope. | |
321 | * | |
322 | ******************************************************************************/ | |
323 | ||
324 | static acpi_status | |
325 | acpi_db_execution_walk(acpi_handle obj_handle, | |
326 | u32 nesting_level, void *context, void **return_value) | |
327 | { | |
328 | union acpi_operand_object *obj_desc; | |
329 | struct acpi_namespace_node *node = | |
330 | (struct acpi_namespace_node *)obj_handle; | |
331 | struct acpi_buffer return_obj; | |
332 | acpi_status status; | |
333 | ||
334 | obj_desc = acpi_ns_get_attached_object(node); | |
335 | if (obj_desc->method.param_count) { | |
336 | return (AE_OK); | |
337 | } | |
338 | ||
339 | return_obj.pointer = NULL; | |
340 | return_obj.length = ACPI_ALLOCATE_BUFFER; | |
341 | ||
342 | acpi_ns_print_node_pathname(node, "Evaluating"); | |
343 | ||
344 | /* Do the actual method execution */ | |
345 | ||
346 | acpi_os_printf("\n"); | |
347 | acpi_gbl_method_executing = TRUE; | |
348 | ||
349 | status = acpi_evaluate_object(node, NULL, NULL, &return_obj); | |
350 | ||
351 | acpi_os_printf("Evaluation of [%4.4s] returned %s\n", | |
352 | acpi_ut_get_node_name(node), | |
353 | acpi_format_exception(status)); | |
354 | ||
355 | acpi_gbl_method_executing = FALSE; | |
356 | return (AE_OK); | |
357 | } | |
358 | ||
359 | /******************************************************************************* | |
360 | * | |
361 | * FUNCTION: acpi_db_execute | |
362 | * | |
363 | * PARAMETERS: name - Name of method to execute | |
364 | * args - Parameters to the method | |
365 | * Types - | |
366 | * flags - single step/no single step | |
367 | * | |
368 | * RETURN: None | |
369 | * | |
370 | * DESCRIPTION: Execute a control method. Name is relative to the current | |
371 | * scope. | |
372 | * | |
373 | ******************************************************************************/ | |
374 | ||
375 | void | |
f5c1e1c5 | 376 | acpi_db_execute(char *name, char **args, acpi_object_type *types, u32 flags) |
99575102 LZ |
377 | { |
378 | acpi_status status; | |
379 | struct acpi_buffer return_obj; | |
380 | char *name_string; | |
381 | ||
382 | #ifdef ACPI_DEBUG_OUTPUT | |
383 | u32 previous_allocations; | |
384 | u32 allocations; | |
aaa93a61 | 385 | #endif |
99575102 | 386 | |
aaa93a61 LZ |
387 | /* |
388 | * Allow one execution to be performed by debugger or single step | |
389 | * execution will be dead locked by the interpreter mutexes. | |
390 | */ | |
391 | if (acpi_gbl_method_executing) { | |
392 | acpi_os_printf("Only one debugger execution is allowed.\n"); | |
393 | return; | |
394 | } | |
395 | #ifdef ACPI_DEBUG_OUTPUT | |
99575102 LZ |
396 | /* Memory allocation tracking */ |
397 | ||
398 | previous_allocations = acpi_db_get_outstanding_allocations(); | |
399 | #endif | |
400 | ||
401 | if (*name == '*') { | |
402 | (void)acpi_walk_namespace(ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT, | |
403 | ACPI_UINT32_MAX, | |
404 | acpi_db_execution_walk, NULL, NULL, | |
405 | NULL); | |
406 | return; | |
60361b75 | 407 | } |
99575102 | 408 | |
60361b75 BM |
409 | name_string = ACPI_ALLOCATE(strlen(name) + 1); |
410 | if (!name_string) { | |
411 | return; | |
412 | } | |
99575102 | 413 | |
60361b75 BM |
414 | memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info)); |
415 | strcpy(name_string, name); | |
416 | acpi_ut_strupr(name_string); | |
99575102 | 417 | |
60361b75 | 418 | /* Subcommand to Execute all predefined names in the namespace */ |
99575102 | 419 | |
60361b75 BM |
420 | if (!strncmp(name_string, "PREDEF", 6)) { |
421 | acpi_db_evaluate_predefined_names(); | |
422 | ACPI_FREE(name_string); | |
423 | return; | |
424 | } | |
99575102 | 425 | |
60361b75 BM |
426 | acpi_gbl_db_method_info.name = name_string; |
427 | acpi_gbl_db_method_info.args = args; | |
428 | acpi_gbl_db_method_info.types = types; | |
429 | acpi_gbl_db_method_info.flags = flags; | |
99575102 | 430 | |
60361b75 BM |
431 | return_obj.pointer = NULL; |
432 | return_obj.length = ACPI_ALLOCATE_BUFFER; | |
433 | ||
434 | status = acpi_db_execute_setup(&acpi_gbl_db_method_info); | |
435 | if (ACPI_FAILURE(status)) { | |
99575102 | 436 | ACPI_FREE(name_string); |
60361b75 BM |
437 | return; |
438 | } | |
439 | ||
440 | /* Get the NS node, determines existence also */ | |
441 | ||
442 | status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname, | |
443 | &acpi_gbl_db_method_info.method); | |
444 | if (ACPI_SUCCESS(status)) { | |
445 | status = acpi_db_execute_method(&acpi_gbl_db_method_info, | |
446 | &return_obj); | |
99575102 | 447 | } |
60361b75 | 448 | ACPI_FREE(name_string); |
99575102 LZ |
449 | |
450 | /* | |
451 | * Allow any handlers in separate threads to complete. | |
452 | * (Such as Notify handlers invoked from AML executed above). | |
453 | */ | |
454 | acpi_os_sleep((u64)10); | |
455 | ||
456 | #ifdef ACPI_DEBUG_OUTPUT | |
457 | ||
458 | /* Memory allocation tracking */ | |
459 | ||
460 | allocations = | |
461 | acpi_db_get_outstanding_allocations() - previous_allocations; | |
462 | ||
463 | acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); | |
464 | ||
465 | if (allocations > 0) { | |
466 | acpi_os_printf | |
467 | ("0x%X Outstanding allocations after evaluation of %s\n", | |
468 | allocations, acpi_gbl_db_method_info.pathname); | |
469 | } | |
470 | #endif | |
471 | ||
472 | if (ACPI_FAILURE(status)) { | |
473 | acpi_os_printf("Evaluation of %s failed with status %s\n", | |
474 | acpi_gbl_db_method_info.pathname, | |
475 | acpi_format_exception(status)); | |
476 | } else { | |
477 | /* Display a return object, if any */ | |
478 | ||
479 | if (return_obj.length) { | |
480 | acpi_os_printf("Evaluation of %s returned object %p, " | |
481 | "external buffer length %X\n", | |
482 | acpi_gbl_db_method_info.pathname, | |
483 | return_obj.pointer, | |
484 | (u32)return_obj.length); | |
485 | ||
486 | acpi_db_dump_external_object(return_obj.pointer, 1); | |
487 | ||
488 | /* Dump a _PLD buffer if present */ | |
489 | ||
490 | if (ACPI_COMPARE_NAME | |
491 | ((ACPI_CAST_PTR | |
492 | (struct acpi_namespace_node, | |
493 | acpi_gbl_db_method_info.method)->name.ascii), | |
494 | METHOD_NAME__PLD)) { | |
495 | acpi_db_dump_pld_buffer(return_obj.pointer); | |
496 | } | |
497 | } else { | |
498 | acpi_os_printf | |
499 | ("No object was returned from evaluation of %s\n", | |
500 | acpi_gbl_db_method_info.pathname); | |
501 | } | |
502 | } | |
503 | ||
504 | acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); | |
505 | } | |
506 | ||
507 | /******************************************************************************* | |
508 | * | |
509 | * FUNCTION: acpi_db_method_thread | |
510 | * | |
511 | * PARAMETERS: context - Execution info segment | |
512 | * | |
513 | * RETURN: None | |
514 | * | |
515 | * DESCRIPTION: Debugger execute thread. Waits for a command line, then | |
516 | * simply dispatches it. | |
517 | * | |
518 | ******************************************************************************/ | |
519 | ||
520 | static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context) | |
521 | { | |
522 | acpi_status status; | |
523 | struct acpi_db_method_info *info = context; | |
524 | struct acpi_db_method_info local_info; | |
525 | u32 i; | |
526 | u8 allow; | |
527 | struct acpi_buffer return_obj; | |
528 | ||
529 | /* | |
530 | * acpi_gbl_db_method_info.Arguments will be passed as method arguments. | |
531 | * Prevent acpi_gbl_db_method_info from being modified by multiple threads | |
532 | * concurrently. | |
533 | * | |
534 | * Note: The arguments we are passing are used by the ASL test suite | |
535 | * (aslts). Do not change them without updating the tests. | |
536 | */ | |
537 | (void)acpi_os_wait_semaphore(info->info_gate, 1, ACPI_WAIT_FOREVER); | |
538 | ||
539 | if (info->init_args) { | |
540 | acpi_db_uint32_to_hex_string(info->num_created, | |
541 | info->index_of_thread_str); | |
542 | acpi_db_uint32_to_hex_string((u32)acpi_os_get_thread_id(), | |
543 | info->id_of_thread_str); | |
544 | } | |
545 | ||
546 | if (info->threads && (info->num_created < info->num_threads)) { | |
547 | info->threads[info->num_created++] = acpi_os_get_thread_id(); | |
548 | } | |
549 | ||
550 | local_info = *info; | |
551 | local_info.args = local_info.arguments; | |
552 | local_info.arguments[0] = local_info.num_threads_str; | |
553 | local_info.arguments[1] = local_info.id_of_thread_str; | |
554 | local_info.arguments[2] = local_info.index_of_thread_str; | |
555 | local_info.arguments[3] = NULL; | |
556 | ||
557 | local_info.types = local_info.arg_types; | |
558 | ||
559 | (void)acpi_os_signal_semaphore(info->info_gate, 1); | |
560 | ||
561 | for (i = 0; i < info->num_loops; i++) { | |
562 | status = acpi_db_execute_method(&local_info, &return_obj); | |
563 | if (ACPI_FAILURE(status)) { | |
564 | acpi_os_printf | |
565 | ("%s During evaluation of %s at iteration %X\n", | |
566 | acpi_format_exception(status), info->pathname, i); | |
567 | if (status == AE_ABORT_METHOD) { | |
568 | break; | |
569 | } | |
570 | } | |
571 | #if 0 | |
572 | if ((i % 100) == 0) { | |
573 | acpi_os_printf("%u loops, Thread 0x%x\n", | |
574 | i, acpi_os_get_thread_id()); | |
575 | } | |
576 | ||
577 | if (return_obj.length) { | |
578 | acpi_os_printf | |
579 | ("Evaluation of %s returned object %p Buflen %X\n", | |
580 | info->pathname, return_obj.pointer, | |
581 | (u32)return_obj.length); | |
582 | acpi_db_dump_external_object(return_obj.pointer, 1); | |
583 | } | |
584 | #endif | |
585 | } | |
586 | ||
587 | /* Signal our completion */ | |
588 | ||
589 | allow = 0; | |
590 | (void)acpi_os_wait_semaphore(info->thread_complete_gate, | |
591 | 1, ACPI_WAIT_FOREVER); | |
592 | info->num_completed++; | |
593 | ||
594 | if (info->num_completed == info->num_threads) { | |
595 | ||
596 | /* Do signal for main thread once only */ | |
597 | allow = 1; | |
598 | } | |
599 | ||
600 | (void)acpi_os_signal_semaphore(info->thread_complete_gate, 1); | |
601 | ||
602 | if (allow) { | |
603 | status = acpi_os_signal_semaphore(info->main_thread_gate, 1); | |
604 | if (ACPI_FAILURE(status)) { | |
605 | acpi_os_printf | |
606 | ("Could not signal debugger thread sync semaphore, %s\n", | |
607 | acpi_format_exception(status)); | |
608 | } | |
609 | } | |
610 | } | |
611 | ||
612 | /******************************************************************************* | |
613 | * | |
614 | * FUNCTION: acpi_db_create_execution_threads | |
615 | * | |
616 | * PARAMETERS: num_threads_arg - Number of threads to create | |
617 | * num_loops_arg - Loop count for the thread(s) | |
618 | * method_name_arg - Control method to execute | |
619 | * | |
620 | * RETURN: None | |
621 | * | |
622 | * DESCRIPTION: Create threads to execute method(s) | |
623 | * | |
624 | ******************************************************************************/ | |
625 | ||
626 | void | |
627 | acpi_db_create_execution_threads(char *num_threads_arg, | |
628 | char *num_loops_arg, char *method_name_arg) | |
629 | { | |
630 | acpi_status status; | |
631 | u32 num_threads; | |
632 | u32 num_loops; | |
633 | u32 i; | |
634 | u32 size; | |
635 | acpi_mutex main_thread_gate; | |
636 | acpi_mutex thread_complete_gate; | |
637 | acpi_mutex info_gate; | |
638 | ||
639 | /* Get the arguments */ | |
640 | ||
641 | num_threads = strtoul(num_threads_arg, NULL, 0); | |
642 | num_loops = strtoul(num_loops_arg, NULL, 0); | |
643 | ||
644 | if (!num_threads || !num_loops) { | |
645 | acpi_os_printf("Bad argument: Threads %X, Loops %X\n", | |
646 | num_threads, num_loops); | |
647 | return; | |
648 | } | |
649 | ||
650 | /* | |
651 | * Create the semaphore for synchronization of | |
652 | * the created threads with the main thread. | |
653 | */ | |
654 | status = acpi_os_create_semaphore(1, 0, &main_thread_gate); | |
655 | if (ACPI_FAILURE(status)) { | |
656 | acpi_os_printf("Could not create semaphore for " | |
657 | "synchronization with the main thread, %s\n", | |
658 | acpi_format_exception(status)); | |
659 | return; | |
660 | } | |
661 | ||
662 | /* | |
663 | * Create the semaphore for synchronization | |
664 | * between the created threads. | |
665 | */ | |
666 | status = acpi_os_create_semaphore(1, 1, &thread_complete_gate); | |
667 | if (ACPI_FAILURE(status)) { | |
668 | acpi_os_printf("Could not create semaphore for " | |
669 | "synchronization between the created threads, %s\n", | |
670 | acpi_format_exception(status)); | |
671 | ||
672 | (void)acpi_os_delete_semaphore(main_thread_gate); | |
673 | return; | |
674 | } | |
675 | ||
676 | status = acpi_os_create_semaphore(1, 1, &info_gate); | |
677 | if (ACPI_FAILURE(status)) { | |
678 | acpi_os_printf("Could not create semaphore for " | |
679 | "synchronization of AcpiGbl_DbMethodInfo, %s\n", | |
680 | acpi_format_exception(status)); | |
681 | ||
682 | (void)acpi_os_delete_semaphore(thread_complete_gate); | |
683 | (void)acpi_os_delete_semaphore(main_thread_gate); | |
684 | return; | |
685 | } | |
686 | ||
687 | memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info)); | |
688 | ||
689 | /* Array to store IDs of threads */ | |
690 | ||
691 | acpi_gbl_db_method_info.num_threads = num_threads; | |
692 | size = sizeof(acpi_thread_id) * acpi_gbl_db_method_info.num_threads; | |
693 | ||
694 | acpi_gbl_db_method_info.threads = acpi_os_allocate(size); | |
695 | if (acpi_gbl_db_method_info.threads == NULL) { | |
696 | acpi_os_printf("No memory for thread IDs array\n"); | |
697 | (void)acpi_os_delete_semaphore(main_thread_gate); | |
698 | (void)acpi_os_delete_semaphore(thread_complete_gate); | |
699 | (void)acpi_os_delete_semaphore(info_gate); | |
700 | return; | |
701 | } | |
702 | memset(acpi_gbl_db_method_info.threads, 0, size); | |
703 | ||
704 | /* Setup the context to be passed to each thread */ | |
705 | ||
706 | acpi_gbl_db_method_info.name = method_name_arg; | |
707 | acpi_gbl_db_method_info.flags = 0; | |
708 | acpi_gbl_db_method_info.num_loops = num_loops; | |
709 | acpi_gbl_db_method_info.main_thread_gate = main_thread_gate; | |
710 | acpi_gbl_db_method_info.thread_complete_gate = thread_complete_gate; | |
711 | acpi_gbl_db_method_info.info_gate = info_gate; | |
712 | ||
713 | /* Init arguments to be passed to method */ | |
714 | ||
715 | acpi_gbl_db_method_info.init_args = 1; | |
716 | acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments; | |
717 | acpi_gbl_db_method_info.arguments[0] = | |
718 | acpi_gbl_db_method_info.num_threads_str; | |
719 | acpi_gbl_db_method_info.arguments[1] = | |
720 | acpi_gbl_db_method_info.id_of_thread_str; | |
721 | acpi_gbl_db_method_info.arguments[2] = | |
722 | acpi_gbl_db_method_info.index_of_thread_str; | |
723 | acpi_gbl_db_method_info.arguments[3] = NULL; | |
724 | ||
725 | acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types; | |
726 | acpi_gbl_db_method_info.arg_types[0] = ACPI_TYPE_INTEGER; | |
727 | acpi_gbl_db_method_info.arg_types[1] = ACPI_TYPE_INTEGER; | |
728 | acpi_gbl_db_method_info.arg_types[2] = ACPI_TYPE_INTEGER; | |
729 | ||
730 | acpi_db_uint32_to_hex_string(num_threads, | |
731 | acpi_gbl_db_method_info.num_threads_str); | |
732 | ||
733 | status = acpi_db_execute_setup(&acpi_gbl_db_method_info); | |
734 | if (ACPI_FAILURE(status)) { | |
735 | goto cleanup_and_exit; | |
736 | } | |
737 | ||
738 | /* Get the NS node, determines existence also */ | |
739 | ||
740 | status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname, | |
741 | &acpi_gbl_db_method_info.method); | |
742 | if (ACPI_FAILURE(status)) { | |
743 | acpi_os_printf("%s Could not get handle for %s\n", | |
744 | acpi_format_exception(status), | |
745 | acpi_gbl_db_method_info.pathname); | |
746 | goto cleanup_and_exit; | |
747 | } | |
748 | ||
749 | /* Create the threads */ | |
750 | ||
751 | acpi_os_printf("Creating %X threads to execute %X times each\n", | |
752 | num_threads, num_loops); | |
753 | ||
754 | for (i = 0; i < (num_threads); i++) { | |
755 | status = | |
f988f24e LZ |
756 | acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD, |
757 | acpi_db_method_thread, | |
99575102 LZ |
758 | &acpi_gbl_db_method_info); |
759 | if (ACPI_FAILURE(status)) { | |
760 | break; | |
761 | } | |
762 | } | |
763 | ||
764 | /* Wait for all threads to complete */ | |
765 | ||
766 | (void)acpi_os_wait_semaphore(main_thread_gate, 1, ACPI_WAIT_FOREVER); | |
767 | ||
768 | acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); | |
769 | acpi_os_printf("All threads (%X) have completed\n", num_threads); | |
770 | acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); | |
771 | ||
772 | cleanup_and_exit: | |
773 | ||
774 | /* Cleanup and exit */ | |
775 | ||
776 | (void)acpi_os_delete_semaphore(main_thread_gate); | |
777 | (void)acpi_os_delete_semaphore(thread_complete_gate); | |
778 | (void)acpi_os_delete_semaphore(info_gate); | |
779 | ||
780 | acpi_os_free(acpi_gbl_db_method_info.threads); | |
781 | acpi_gbl_db_method_info.threads = NULL; | |
782 | } |