Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*******************************************************************************
  2.  *
  3.  * Module Name: dbexec - debugger control method execution
  4.  *
  5.  ******************************************************************************/
  6.  
  7. /*
  8.  * Copyright (C) 2000 - 2015, 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/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.                                                            &params[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.                                       &param_objects, return_obj);
  179.  
  180.         acpi_gbl_cm_single_step = FALSE;
  181.         acpi_gbl_method_executing = FALSE;
  182.  
  183.         if (ACPI_FAILURE(status)) {
  184.                 ACPI_EXCEPTION((AE_INFO, status,
  185.                                 "while executing %s from debugger",
  186.                                 info->pathname));
  187.  
  188.                 if (status == AE_BUFFER_OVERFLOW) {
  189.                         ACPI_ERROR((AE_INFO,
  190.                                     "Possible overflow of internal debugger "
  191.                                     "buffer (size 0x%X needed 0x%X)",
  192.                                     ACPI_DEBUG_BUFFER_SIZE,
  193.                                     (u32)return_obj->length));
  194.                 }
  195.         }
  196.  
  197. cleanup:
  198.         acpi_db_delete_objects(param_objects.count, params);
  199.         return_ACPI_STATUS(status);
  200. }
  201.  
  202. /*******************************************************************************
  203.  *
  204.  * FUNCTION:    acpi_db_execute_setup
  205.  *
  206.  * PARAMETERS:  info            - Valid method info
  207.  *
  208.  * RETURN:      None
  209.  *
  210.  * DESCRIPTION: Setup info segment prior to method execution
  211.  *
  212.  ******************************************************************************/
  213.  
  214. static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info)
  215. {
  216.         acpi_status status;
  217.  
  218.         ACPI_FUNCTION_NAME(db_execute_setup);
  219.  
  220.         /* Catenate the current scope to the supplied name */
  221.  
  222.         info->pathname[0] = 0;
  223.         if ((info->name[0] != '\\') && (info->name[0] != '/')) {
  224.                 if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
  225.                                         acpi_gbl_db_scope_buf)) {
  226.                         status = AE_BUFFER_OVERFLOW;
  227.                         goto error_exit;
  228.                 }
  229.         }
  230.  
  231.         if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
  232.                                 info->name)) {
  233.                 status = AE_BUFFER_OVERFLOW;
  234.                 goto error_exit;
  235.         }
  236.  
  237.         acpi_db_prep_namestring(info->pathname);
  238.  
  239.         acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
  240.         acpi_os_printf("Evaluating %s\n", info->pathname);
  241.  
  242.         if (info->flags & EX_SINGLE_STEP) {
  243.                 acpi_gbl_cm_single_step = TRUE;
  244.                 acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
  245.         }
  246.  
  247.         else {
  248.                 /* No single step, allow redirection to a file */
  249.  
  250.                 acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
  251.         }
  252.  
  253.         return (AE_OK);
  254.  
  255. error_exit:
  256.  
  257.         ACPI_EXCEPTION((AE_INFO, status, "During setup for method execution"));
  258.         return (status);
  259. }
  260.  
  261. #ifdef ACPI_DBG_TRACK_ALLOCATIONS
  262. u32 acpi_db_get_cache_info(struct acpi_memory_list *cache)
  263. {
  264.  
  265.         return (cache->total_allocated - cache->total_freed -
  266.                 cache->current_depth);
  267. }
  268. #endif
  269.  
  270. /*******************************************************************************
  271.  *
  272.  * FUNCTION:    acpi_db_get_outstanding_allocations
  273.  *
  274.  * PARAMETERS:  None
  275.  *
  276.  * RETURN:      Current global allocation count minus cache entries
  277.  *
  278.  * DESCRIPTION: Determine the current number of "outstanding" allocations --
  279.  *              those allocations that have not been freed and also are not
  280.  *              in one of the various object caches.
  281.  *
  282.  ******************************************************************************/
  283.  
  284. static u32 acpi_db_get_outstanding_allocations(void)
  285. {
  286.         u32 outstanding = 0;
  287.  
  288. #ifdef ACPI_DBG_TRACK_ALLOCATIONS
  289.  
  290.         outstanding += acpi_db_get_cache_info(acpi_gbl_state_cache);
  291.         outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_cache);
  292.         outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_ext_cache);
  293.         outstanding += acpi_db_get_cache_info(acpi_gbl_operand_cache);
  294. #endif
  295.  
  296.         return (outstanding);
  297. }
  298.  
  299. /*******************************************************************************
  300.  *
  301.  * FUNCTION:    acpi_db_execution_walk
  302.  *
  303.  * PARAMETERS:  WALK_CALLBACK
  304.  *
  305.  * RETURN:      Status
  306.  *
  307.  * DESCRIPTION: Execute a control method. Name is relative to the current
  308.  *              scope.
  309.  *
  310.  ******************************************************************************/
  311.  
  312. static acpi_status
  313. acpi_db_execution_walk(acpi_handle obj_handle,
  314.                        u32 nesting_level, void *context, void **return_value)
  315. {
  316.         union acpi_operand_object *obj_desc;
  317.         struct acpi_namespace_node *node =
  318.             (struct acpi_namespace_node *)obj_handle;
  319.         struct acpi_buffer return_obj;
  320.         acpi_status status;
  321.  
  322.         obj_desc = acpi_ns_get_attached_object(node);
  323.         if (obj_desc->method.param_count) {
  324.                 return (AE_OK);
  325.         }
  326.  
  327.         return_obj.pointer = NULL;
  328.         return_obj.length = ACPI_ALLOCATE_BUFFER;
  329.  
  330.         acpi_ns_print_node_pathname(node, "Evaluating");
  331.  
  332.         /* Do the actual method execution */
  333.  
  334.         acpi_os_printf("\n");
  335.         acpi_gbl_method_executing = TRUE;
  336.  
  337.         status = acpi_evaluate_object(node, NULL, NULL, &return_obj);
  338.  
  339.         acpi_os_printf("Evaluation of [%4.4s] returned %s\n",
  340.                        acpi_ut_get_node_name(node),
  341.                        acpi_format_exception(status));
  342.  
  343.         acpi_gbl_method_executing = FALSE;
  344.         return (AE_OK);
  345. }
  346.  
  347. /*******************************************************************************
  348.  *
  349.  * FUNCTION:    acpi_db_execute
  350.  *
  351.  * PARAMETERS:  name                - Name of method to execute
  352.  *              args                - Parameters to the method
  353.  *              Types               -
  354.  *              flags               - single step/no single step
  355.  *
  356.  * RETURN:      None
  357.  *
  358.  * DESCRIPTION: Execute a control method. Name is relative to the current
  359.  *              scope.
  360.  *
  361.  ******************************************************************************/
  362.  
  363. void
  364. acpi_db_execute(char *name, char **args, acpi_object_type * types, u32 flags)
  365. {
  366.         acpi_status status;
  367.         struct acpi_buffer return_obj;
  368.         char *name_string;
  369.  
  370. #ifdef ACPI_DEBUG_OUTPUT
  371.         u32 previous_allocations;
  372.         u32 allocations;
  373. #endif
  374.  
  375.         /*
  376.          * Allow one execution to be performed by debugger or single step
  377.          * execution will be dead locked by the interpreter mutexes.
  378.          */
  379.         if (acpi_gbl_method_executing) {
  380.                 acpi_os_printf("Only one debugger execution is allowed.\n");
  381.                 return;
  382.         }
  383. #ifdef ACPI_DEBUG_OUTPUT
  384.         /* Memory allocation tracking */
  385.  
  386.         previous_allocations = acpi_db_get_outstanding_allocations();
  387. #endif
  388.  
  389.         if (*name == '*') {
  390.                 (void)acpi_walk_namespace(ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
  391.                                           ACPI_UINT32_MAX,
  392.                                           acpi_db_execution_walk, NULL, NULL,
  393.                                           NULL);
  394.                 return;
  395.         } else {
  396.                 name_string = ACPI_ALLOCATE(strlen(name) + 1);
  397.                 if (!name_string) {
  398.                         return;
  399.                 }
  400.  
  401.                 memset(&acpi_gbl_db_method_info, 0,
  402.                        sizeof(struct acpi_db_method_info));
  403.  
  404.                 strcpy(name_string, name);
  405.                 acpi_ut_strupr(name_string);
  406.                 acpi_gbl_db_method_info.name = name_string;
  407.                 acpi_gbl_db_method_info.args = args;
  408.                 acpi_gbl_db_method_info.types = types;
  409.                 acpi_gbl_db_method_info.flags = flags;
  410.  
  411.                 return_obj.pointer = NULL;
  412.                 return_obj.length = ACPI_ALLOCATE_BUFFER;
  413.  
  414.                 status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
  415.                 if (ACPI_FAILURE(status)) {
  416.                         ACPI_FREE(name_string);
  417.                         return;
  418.                 }
  419.  
  420.                 /* Get the NS node, determines existence also */
  421.  
  422.                 status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
  423.                                          &acpi_gbl_db_method_info.method);
  424.                 if (ACPI_SUCCESS(status)) {
  425.                         status =
  426.                             acpi_db_execute_method(&acpi_gbl_db_method_info,
  427.                                                    &return_obj);
  428.                 }
  429.                 ACPI_FREE(name_string);
  430.         }
  431.  
  432.         /*
  433.          * Allow any handlers in separate threads to complete.
  434.          * (Such as Notify handlers invoked from AML executed above).
  435.          */
  436.         acpi_os_sleep((u64)10);
  437.  
  438. #ifdef ACPI_DEBUG_OUTPUT
  439.  
  440.         /* Memory allocation tracking */
  441.  
  442.         allocations =
  443.             acpi_db_get_outstanding_allocations() - previous_allocations;
  444.  
  445.         acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
  446.  
  447.         if (allocations > 0) {
  448.                 acpi_os_printf
  449.                     ("0x%X Outstanding allocations after evaluation of %s\n",
  450.                      allocations, acpi_gbl_db_method_info.pathname);
  451.         }
  452. #endif
  453.  
  454.         if (ACPI_FAILURE(status)) {
  455.                 acpi_os_printf("Evaluation of %s failed with status %s\n",
  456.                                acpi_gbl_db_method_info.pathname,
  457.                                acpi_format_exception(status));
  458.         } else {
  459.                 /* Display a return object, if any */
  460.  
  461.                 if (return_obj.length) {
  462.                         acpi_os_printf("Evaluation of %s returned object %p, "
  463.                                        "external buffer length %X\n",
  464.                                        acpi_gbl_db_method_info.pathname,
  465.                                        return_obj.pointer,
  466.                                        (u32)return_obj.length);
  467.  
  468.                         acpi_db_dump_external_object(return_obj.pointer, 1);
  469.  
  470.                         /* Dump a _PLD buffer if present */
  471.  
  472.                         if (ACPI_COMPARE_NAME
  473.                             ((ACPI_CAST_PTR
  474.                               (struct acpi_namespace_node,
  475.                                acpi_gbl_db_method_info.method)->name.ascii),
  476.                              METHOD_NAME__PLD)) {
  477.                                 acpi_db_dump_pld_buffer(return_obj.pointer);
  478.                         }
  479.                 } else {
  480.                         acpi_os_printf
  481.                             ("No object was returned from evaluation of %s\n",
  482.                              acpi_gbl_db_method_info.pathname);
  483.                 }
  484.         }
  485.  
  486.         acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
  487. }
  488.  
  489. /*******************************************************************************
  490.  *
  491.  * FUNCTION:    acpi_db_method_thread
  492.  *
  493.  * PARAMETERS:  context             - Execution info segment
  494.  *
  495.  * RETURN:      None
  496.  *
  497.  * DESCRIPTION: Debugger execute thread. Waits for a command line, then
  498.  *              simply dispatches it.
  499.  *
  500.  ******************************************************************************/
  501.  
  502. static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context)
  503. {
  504.         acpi_status status;
  505.         struct acpi_db_method_info *info = context;
  506.         struct acpi_db_method_info local_info;
  507.         u32 i;
  508.         u8 allow;
  509.         struct acpi_buffer return_obj;
  510.  
  511.         /*
  512.          * acpi_gbl_db_method_info.Arguments will be passed as method arguments.
  513.          * Prevent acpi_gbl_db_method_info from being modified by multiple threads
  514.          * concurrently.
  515.          *
  516.          * Note: The arguments we are passing are used by the ASL test suite
  517.          * (aslts). Do not change them without updating the tests.
  518.          */
  519.         (void)acpi_os_wait_semaphore(info->info_gate, 1, ACPI_WAIT_FOREVER);
  520.  
  521.         if (info->init_args) {
  522.                 acpi_db_uint32_to_hex_string(info->num_created,
  523.                                              info->index_of_thread_str);
  524.                 acpi_db_uint32_to_hex_string((u32)acpi_os_get_thread_id(),
  525.                                              info->id_of_thread_str);
  526.         }
  527.  
  528.         if (info->threads && (info->num_created < info->num_threads)) {
  529.                 info->threads[info->num_created++] = acpi_os_get_thread_id();
  530.         }
  531.  
  532.         local_info = *info;
  533.         local_info.args = local_info.arguments;
  534.         local_info.arguments[0] = local_info.num_threads_str;
  535.         local_info.arguments[1] = local_info.id_of_thread_str;
  536.         local_info.arguments[2] = local_info.index_of_thread_str;
  537.         local_info.arguments[3] = NULL;
  538.  
  539.         local_info.types = local_info.arg_types;
  540.  
  541.         (void)acpi_os_signal_semaphore(info->info_gate, 1);
  542.  
  543.         for (i = 0; i < info->num_loops; i++) {
  544.                 status = acpi_db_execute_method(&local_info, &return_obj);
  545.                 if (ACPI_FAILURE(status)) {
  546.                         acpi_os_printf
  547.                             ("%s During evaluation of %s at iteration %X\n",
  548.                              acpi_format_exception(status), info->pathname, i);
  549.                         if (status == AE_ABORT_METHOD) {
  550.                                 break;
  551.                         }
  552.                 }
  553. #if 0
  554.                 if ((i % 100) == 0) {
  555.                         acpi_os_printf("%u loops, Thread 0x%x\n",
  556.                                        i, acpi_os_get_thread_id());
  557.                 }
  558.  
  559.                 if (return_obj.length) {
  560.                         acpi_os_printf
  561.                             ("Evaluation of %s returned object %p Buflen %X\n",
  562.                              info->pathname, return_obj.pointer,
  563.                              (u32)return_obj.length);
  564.                         acpi_db_dump_external_object(return_obj.pointer, 1);
  565.                 }
  566. #endif
  567.         }
  568.  
  569.         /* Signal our completion */
  570.  
  571.         allow = 0;
  572.         (void)acpi_os_wait_semaphore(info->thread_complete_gate,
  573.                                      1, ACPI_WAIT_FOREVER);
  574.         info->num_completed++;
  575.  
  576.         if (info->num_completed == info->num_threads) {
  577.  
  578.                 /* Do signal for main thread once only */
  579.                 allow = 1;
  580.         }
  581.  
  582.         (void)acpi_os_signal_semaphore(info->thread_complete_gate, 1);
  583.  
  584.         if (allow) {
  585.                 status = acpi_os_signal_semaphore(info->main_thread_gate, 1);
  586.                 if (ACPI_FAILURE(status)) {
  587.                         acpi_os_printf
  588.                             ("Could not signal debugger thread sync semaphore, %s\n",
  589.                              acpi_format_exception(status));
  590.                 }
  591.         }
  592. }
  593.  
  594. /*******************************************************************************
  595.  *
  596.  * FUNCTION:    acpi_db_create_execution_threads
  597.  *
  598.  * PARAMETERS:  num_threads_arg         - Number of threads to create
  599.  *              num_loops_arg           - Loop count for the thread(s)
  600.  *              method_name_arg         - Control method to execute
  601.  *
  602.  * RETURN:      None
  603.  *
  604.  * DESCRIPTION: Create threads to execute method(s)
  605.  *
  606.  ******************************************************************************/
  607.  
  608. void
  609. acpi_db_create_execution_threads(char *num_threads_arg,
  610.                                  char *num_loops_arg, char *method_name_arg)
  611. {
  612.         acpi_status status;
  613.         u32 num_threads;
  614.         u32 num_loops;
  615.         u32 i;
  616.         u32 size;
  617.         acpi_mutex main_thread_gate;
  618.         acpi_mutex thread_complete_gate;
  619.         acpi_mutex info_gate;
  620.  
  621.         /* Get the arguments */
  622.  
  623.         num_threads = strtoul(num_threads_arg, NULL, 0);
  624.         num_loops = strtoul(num_loops_arg, NULL, 0);
  625.  
  626.         if (!num_threads || !num_loops) {
  627.                 acpi_os_printf("Bad argument: Threads %X, Loops %X\n",
  628.                                num_threads, num_loops);
  629.                 return;
  630.         }
  631.  
  632.         /*
  633.          * Create the semaphore for synchronization of
  634.          * the created threads with the main thread.
  635.          */
  636.         status = acpi_os_create_semaphore(1, 0, &main_thread_gate);
  637.         if (ACPI_FAILURE(status)) {
  638.                 acpi_os_printf("Could not create semaphore for "
  639.                                "synchronization with the main thread, %s\n",
  640.                                acpi_format_exception(status));
  641.                 return;
  642.         }
  643.  
  644.         /*
  645.          * Create the semaphore for synchronization
  646.          * between the created threads.
  647.          */
  648.         status = acpi_os_create_semaphore(1, 1, &thread_complete_gate);
  649.         if (ACPI_FAILURE(status)) {
  650.                 acpi_os_printf("Could not create semaphore for "
  651.                                "synchronization between the created threads, %s\n",
  652.                                acpi_format_exception(status));
  653.  
  654.                 (void)acpi_os_delete_semaphore(main_thread_gate);
  655.                 return;
  656.         }
  657.  
  658.         status = acpi_os_create_semaphore(1, 1, &info_gate);
  659.         if (ACPI_FAILURE(status)) {
  660.                 acpi_os_printf("Could not create semaphore for "
  661.                                "synchronization of AcpiGbl_DbMethodInfo, %s\n",
  662.                                acpi_format_exception(status));
  663.  
  664.                 (void)acpi_os_delete_semaphore(thread_complete_gate);
  665.                 (void)acpi_os_delete_semaphore(main_thread_gate);
  666.                 return;
  667.         }
  668.  
  669.         memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
  670.  
  671.         /* Array to store IDs of threads */
  672.  
  673.         acpi_gbl_db_method_info.num_threads = num_threads;
  674.         size = sizeof(acpi_thread_id) * acpi_gbl_db_method_info.num_threads;
  675.  
  676.         acpi_gbl_db_method_info.threads = acpi_os_allocate(size);
  677.         if (acpi_gbl_db_method_info.threads == NULL) {
  678.                 acpi_os_printf("No memory for thread IDs array\n");
  679.                 (void)acpi_os_delete_semaphore(main_thread_gate);
  680.                 (void)acpi_os_delete_semaphore(thread_complete_gate);
  681.                 (void)acpi_os_delete_semaphore(info_gate);
  682.                 return;
  683.         }
  684.         memset(acpi_gbl_db_method_info.threads, 0, size);
  685.  
  686.         /* Setup the context to be passed to each thread */
  687.  
  688.         acpi_gbl_db_method_info.name = method_name_arg;
  689.         acpi_gbl_db_method_info.flags = 0;
  690.         acpi_gbl_db_method_info.num_loops = num_loops;
  691.         acpi_gbl_db_method_info.main_thread_gate = main_thread_gate;
  692.         acpi_gbl_db_method_info.thread_complete_gate = thread_complete_gate;
  693.         acpi_gbl_db_method_info.info_gate = info_gate;
  694.  
  695.         /* Init arguments to be passed to method */
  696.  
  697.         acpi_gbl_db_method_info.init_args = 1;
  698.         acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
  699.         acpi_gbl_db_method_info.arguments[0] =
  700.             acpi_gbl_db_method_info.num_threads_str;
  701.         acpi_gbl_db_method_info.arguments[1] =
  702.             acpi_gbl_db_method_info.id_of_thread_str;
  703.         acpi_gbl_db_method_info.arguments[2] =
  704.             acpi_gbl_db_method_info.index_of_thread_str;
  705.         acpi_gbl_db_method_info.arguments[3] = NULL;
  706.  
  707.         acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
  708.         acpi_gbl_db_method_info.arg_types[0] = ACPI_TYPE_INTEGER;
  709.         acpi_gbl_db_method_info.arg_types[1] = ACPI_TYPE_INTEGER;
  710.         acpi_gbl_db_method_info.arg_types[2] = ACPI_TYPE_INTEGER;
  711.  
  712.         acpi_db_uint32_to_hex_string(num_threads,
  713.                                      acpi_gbl_db_method_info.num_threads_str);
  714.  
  715.         status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
  716.         if (ACPI_FAILURE(status)) {
  717.                 goto cleanup_and_exit;
  718.         }
  719.  
  720.         /* Get the NS node, determines existence also */
  721.  
  722.         status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
  723.                                  &acpi_gbl_db_method_info.method);
  724.         if (ACPI_FAILURE(status)) {
  725.                 acpi_os_printf("%s Could not get handle for %s\n",
  726.                                acpi_format_exception(status),
  727.                                acpi_gbl_db_method_info.pathname);
  728.                 goto cleanup_and_exit;
  729.         }
  730.  
  731.         /* Create the threads */
  732.  
  733.         acpi_os_printf("Creating %X threads to execute %X times each\n",
  734.                        num_threads, num_loops);
  735.  
  736.         for (i = 0; i < (num_threads); i++) {
  737.                 status =
  738.                     acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
  739.                                     acpi_db_method_thread,
  740.                                     &acpi_gbl_db_method_info);
  741.                 if (ACPI_FAILURE(status)) {
  742.                         break;
  743.                 }
  744.         }
  745.  
  746.         /* Wait for all threads to complete */
  747.  
  748.         (void)acpi_os_wait_semaphore(main_thread_gate, 1, ACPI_WAIT_FOREVER);
  749.  
  750.         acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
  751.         acpi_os_printf("All threads (%X) have completed\n", num_threads);
  752.         acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
  753.  
  754. cleanup_and_exit:
  755.  
  756.         /* Cleanup and exit */
  757.  
  758.         (void)acpi_os_delete_semaphore(main_thread_gate);
  759.         (void)acpi_os_delete_semaphore(thread_complete_gate);
  760.         (void)acpi_os_delete_semaphore(info_gate);
  761.  
  762.         acpi_os_free(acpi_gbl_db_method_info.threads);
  763.         acpi_gbl_db_method_info.threads = NULL;
  764. }
  765.