2015-10-19 05:25:20 +03:00
/*******************************************************************************
*
* Module Name : dbexec - debugger control method execution
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
2016-01-15 03:17:03 +03:00
* Copyright ( C ) 2000 - 2016 , Intel Corp .
2015-10-19 05:25:20 +03:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions , and the following disclaimer ,
* without modification .
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the " NO WARRANTY " disclaimer below
* ( " Disclaimer " ) and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution .
* 3. Neither the names of the above - listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* Alternatively , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) version 2 as published by the Free
* Software Foundation .
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT ,
* STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES .
*/
# include <acpi/acpi.h>
# include "accommon.h"
# include "acdebug.h"
# include "acnamesp.h"
# define _COMPONENT ACPI_CA_DEBUGGER
ACPI_MODULE_NAME ( " dbexec " )
static struct acpi_db_method_info acpi_gbl_db_method_info ;
/* Local prototypes */
static acpi_status
acpi_db_execute_method ( struct acpi_db_method_info * info ,
struct acpi_buffer * return_obj ) ;
static acpi_status acpi_db_execute_setup ( struct acpi_db_method_info * info ) ;
static u32 acpi_db_get_outstanding_allocations ( void ) ;
static void ACPI_SYSTEM_XFACE acpi_db_method_thread ( void * context ) ;
static acpi_status
acpi_db_execution_walk ( acpi_handle obj_handle ,
u32 nesting_level , void * context , void * * return_value ) ;
/*******************************************************************************
*
* FUNCTION : acpi_db_delete_objects
*
* PARAMETERS : count - Count of objects in the list
* objects - Array of ACPI_OBJECTs to be deleted
*
* RETURN : None
*
* DESCRIPTION : Delete a list of ACPI_OBJECTS . Handles packages and nested
* packages via recursion .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void acpi_db_delete_objects ( u32 count , union acpi_object * objects )
{
u32 i ;
for ( i = 0 ; i < count ; i + + ) {
switch ( objects [ i ] . type ) {
case ACPI_TYPE_BUFFER :
ACPI_FREE ( objects [ i ] . buffer . pointer ) ;
break ;
case ACPI_TYPE_PACKAGE :
/* Recursive call to delete package elements */
acpi_db_delete_objects ( objects [ i ] . package . count ,
objects [ i ] . package . elements ) ;
/* Free the elements array */
ACPI_FREE ( objects [ i ] . package . elements ) ;
break ;
default :
break ;
}
}
}
/*******************************************************************************
*
* FUNCTION : acpi_db_execute_method
*
* PARAMETERS : info - Valid info segment
* return_obj - Where to put return object
*
* RETURN : Status
*
* DESCRIPTION : Execute a control method .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static acpi_status
acpi_db_execute_method ( struct acpi_db_method_info * info ,
struct acpi_buffer * return_obj )
{
acpi_status status ;
struct acpi_object_list param_objects ;
union acpi_object params [ ACPI_DEBUGGER_MAX_ARGS + 1 ] ;
u32 i ;
ACPI_FUNCTION_TRACE ( db_execute_method ) ;
if ( acpi_gbl_db_output_to_file & & ! acpi_dbg_level ) {
acpi_os_printf ( " Warning: debug output is not enabled! \n " ) ;
}
param_objects . count = 0 ;
param_objects . pointer = NULL ;
/* Pass through any command-line arguments */
if ( info - > args & & info - > args [ 0 ] ) {
/* Get arguments passed on the command line */
for ( i = 0 ; ( info - > args [ i ] & & * ( info - > args [ i ] ) ) ; i + + ) {
/* Convert input string (token) to an actual union acpi_object */
status = acpi_db_convert_to_object ( info - > types [ i ] ,
info - > args [ i ] ,
& params [ i ] ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_EXCEPTION ( ( AE_INFO , status ,
" While parsing method arguments " ) ) ;
goto cleanup ;
}
}
param_objects . count = i ;
param_objects . pointer = params ;
}
/* Prepare for a return object of arbitrary size */
return_obj - > pointer = acpi_gbl_db_buffer ;
return_obj - > length = ACPI_DEBUG_BUFFER_SIZE ;
/* Do the actual method execution */
acpi_gbl_method_executing = TRUE ;
status = acpi_evaluate_object ( NULL , info - > pathname ,
& param_objects , return_obj ) ;
acpi_gbl_cm_single_step = FALSE ;
acpi_gbl_method_executing = FALSE ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_EXCEPTION ( ( AE_INFO , status ,
" while executing %s from debugger " ,
info - > pathname ) ) ;
if ( status = = AE_BUFFER_OVERFLOW ) {
ACPI_ERROR ( ( AE_INFO ,
" Possible overflow of internal debugger "
" buffer (size 0x%X needed 0x%X) " ,
ACPI_DEBUG_BUFFER_SIZE ,
( u32 ) return_obj - > length ) ) ;
}
}
cleanup :
acpi_db_delete_objects ( param_objects . count , params ) ;
return_ACPI_STATUS ( status ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_db_execute_setup
*
* PARAMETERS : info - Valid method info
*
* RETURN : None
*
* DESCRIPTION : Setup info segment prior to method execution
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static acpi_status acpi_db_execute_setup ( struct acpi_db_method_info * info )
{
acpi_status status ;
ACPI_FUNCTION_NAME ( db_execute_setup ) ;
/* Catenate the current scope to the supplied name */
info - > pathname [ 0 ] = 0 ;
if ( ( info - > name [ 0 ] ! = ' \\ ' ) & & ( info - > name [ 0 ] ! = ' / ' ) ) {
if ( acpi_ut_safe_strcat ( info - > pathname , sizeof ( info - > pathname ) ,
acpi_gbl_db_scope_buf ) ) {
status = AE_BUFFER_OVERFLOW ;
goto error_exit ;
}
}
if ( acpi_ut_safe_strcat ( info - > pathname , sizeof ( info - > pathname ) ,
info - > name ) ) {
status = AE_BUFFER_OVERFLOW ;
goto error_exit ;
}
acpi_db_prep_namestring ( info - > pathname ) ;
acpi_db_set_output_destination ( ACPI_DB_DUPLICATE_OUTPUT ) ;
acpi_os_printf ( " Evaluating %s \n " , info - > pathname ) ;
if ( info - > flags & EX_SINGLE_STEP ) {
acpi_gbl_cm_single_step = TRUE ;
acpi_db_set_output_destination ( ACPI_DB_CONSOLE_OUTPUT ) ;
}
else {
/* No single step, allow redirection to a file */
acpi_db_set_output_destination ( ACPI_DB_REDIRECTABLE_OUTPUT ) ;
}
return ( AE_OK ) ;
error_exit :
ACPI_EXCEPTION ( ( AE_INFO , status , " During setup for method execution " ) ) ;
return ( status ) ;
}
# ifdef ACPI_DBG_TRACK_ALLOCATIONS
u32 acpi_db_get_cache_info ( struct acpi_memory_list * cache )
{
return ( cache - > total_allocated - cache - > total_freed -
cache - > current_depth ) ;
}
# endif
/*******************************************************************************
*
* FUNCTION : acpi_db_get_outstanding_allocations
*
* PARAMETERS : None
*
* RETURN : Current global allocation count minus cache entries
*
* DESCRIPTION : Determine the current number of " outstanding " allocations - -
* those allocations that have not been freed and also are not
* in one of the various object caches .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static u32 acpi_db_get_outstanding_allocations ( void )
{
u32 outstanding = 0 ;
# ifdef ACPI_DBG_TRACK_ALLOCATIONS
outstanding + = acpi_db_get_cache_info ( acpi_gbl_state_cache ) ;
outstanding + = acpi_db_get_cache_info ( acpi_gbl_ps_node_cache ) ;
outstanding + = acpi_db_get_cache_info ( acpi_gbl_ps_node_ext_cache ) ;
outstanding + = acpi_db_get_cache_info ( acpi_gbl_operand_cache ) ;
# endif
return ( outstanding ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_db_execution_walk
*
* PARAMETERS : WALK_CALLBACK
*
* RETURN : Status
*
* DESCRIPTION : Execute a control method . Name is relative to the current
* scope .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static acpi_status
acpi_db_execution_walk ( acpi_handle obj_handle ,
u32 nesting_level , void * context , void * * return_value )
{
union acpi_operand_object * obj_desc ;
struct acpi_namespace_node * node =
( struct acpi_namespace_node * ) obj_handle ;
struct acpi_buffer return_obj ;
acpi_status status ;
obj_desc = acpi_ns_get_attached_object ( node ) ;
if ( obj_desc - > method . param_count ) {
return ( AE_OK ) ;
}
return_obj . pointer = NULL ;
return_obj . length = ACPI_ALLOCATE_BUFFER ;
acpi_ns_print_node_pathname ( node , " Evaluating " ) ;
/* Do the actual method execution */
acpi_os_printf ( " \n " ) ;
acpi_gbl_method_executing = TRUE ;
status = acpi_evaluate_object ( node , NULL , NULL , & return_obj ) ;
acpi_os_printf ( " Evaluation of [%4.4s] returned %s \n " ,
acpi_ut_get_node_name ( node ) ,
acpi_format_exception ( status ) ) ;
acpi_gbl_method_executing = FALSE ;
return ( AE_OK ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_db_execute
*
* PARAMETERS : name - Name of method to execute
* args - Parameters to the method
* Types -
* flags - single step / no single step
*
* RETURN : None
*
* DESCRIPTION : Execute a control method . Name is relative to the current
* scope .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
2016-05-05 07:57:53 +03:00
acpi_db_execute ( char * name , char * * args , acpi_object_type * types , u32 flags )
2015-10-19 05:25:20 +03:00
{
acpi_status status ;
struct acpi_buffer return_obj ;
char * name_string ;
# ifdef ACPI_DEBUG_OUTPUT
u32 previous_allocations ;
u32 allocations ;
2015-10-19 05:26:02 +03:00
# endif
2015-10-19 05:25:20 +03:00
2015-10-19 05:26:02 +03:00
/*
* Allow one execution to be performed by debugger or single step
* execution will be dead locked by the interpreter mutexes .
*/
if ( acpi_gbl_method_executing ) {
acpi_os_printf ( " Only one debugger execution is allowed. \n " ) ;
return ;
}
# ifdef ACPI_DEBUG_OUTPUT
2015-10-19 05:25:20 +03:00
/* Memory allocation tracking */
previous_allocations = acpi_db_get_outstanding_allocations ( ) ;
# endif
if ( * name = = ' * ' ) {
( void ) acpi_walk_namespace ( ACPI_TYPE_METHOD , ACPI_ROOT_OBJECT ,
ACPI_UINT32_MAX ,
acpi_db_execution_walk , NULL , NULL ,
NULL ) ;
return ;
2016-09-07 09:05:41 +03:00
}
2015-10-19 05:25:20 +03:00
2016-09-07 09:05:41 +03:00
name_string = ACPI_ALLOCATE ( strlen ( name ) + 1 ) ;
if ( ! name_string ) {
return ;
}
2015-10-19 05:25:20 +03:00
2016-09-07 09:05:41 +03:00
memset ( & acpi_gbl_db_method_info , 0 , sizeof ( struct acpi_db_method_info ) ) ;
strcpy ( name_string , name ) ;
acpi_ut_strupr ( name_string ) ;
2015-10-19 05:25:20 +03:00
2016-09-07 09:05:41 +03:00
/* Subcommand to Execute all predefined names in the namespace */
2015-10-19 05:25:20 +03:00
2016-09-07 09:05:41 +03:00
if ( ! strncmp ( name_string , " PREDEF " , 6 ) ) {
acpi_db_evaluate_predefined_names ( ) ;
ACPI_FREE ( name_string ) ;
return ;
}
2015-10-19 05:25:20 +03:00
2016-09-07 09:05:41 +03:00
acpi_gbl_db_method_info . name = name_string ;
acpi_gbl_db_method_info . args = args ;
acpi_gbl_db_method_info . types = types ;
acpi_gbl_db_method_info . flags = flags ;
2015-10-19 05:25:20 +03:00
2016-09-07 09:05:41 +03:00
return_obj . pointer = NULL ;
return_obj . length = ACPI_ALLOCATE_BUFFER ;
status = acpi_db_execute_setup ( & acpi_gbl_db_method_info ) ;
if ( ACPI_FAILURE ( status ) ) {
2015-10-19 05:25:20 +03:00
ACPI_FREE ( name_string ) ;
2016-09-07 09:05:41 +03:00
return ;
}
/* Get the NS node, determines existence also */
status = acpi_get_handle ( NULL , acpi_gbl_db_method_info . pathname ,
& acpi_gbl_db_method_info . method ) ;
if ( ACPI_SUCCESS ( status ) ) {
status = acpi_db_execute_method ( & acpi_gbl_db_method_info ,
& return_obj ) ;
2015-10-19 05:25:20 +03:00
}
2016-09-07 09:05:41 +03:00
ACPI_FREE ( name_string ) ;
2015-10-19 05:25:20 +03:00
/*
* Allow any handlers in separate threads to complete .
* ( Such as Notify handlers invoked from AML executed above ) .
*/
acpi_os_sleep ( ( u64 ) 10 ) ;
# ifdef ACPI_DEBUG_OUTPUT
/* Memory allocation tracking */
allocations =
acpi_db_get_outstanding_allocations ( ) - previous_allocations ;
acpi_db_set_output_destination ( ACPI_DB_DUPLICATE_OUTPUT ) ;
if ( allocations > 0 ) {
acpi_os_printf
( " 0x%X Outstanding allocations after evaluation of %s \n " ,
allocations , acpi_gbl_db_method_info . pathname ) ;
}
# endif
if ( ACPI_FAILURE ( status ) ) {
acpi_os_printf ( " Evaluation of %s failed with status %s \n " ,
acpi_gbl_db_method_info . pathname ,
acpi_format_exception ( status ) ) ;
} else {
/* Display a return object, if any */
if ( return_obj . length ) {
acpi_os_printf ( " Evaluation of %s returned object %p, "
" external buffer length %X \n " ,
acpi_gbl_db_method_info . pathname ,
return_obj . pointer ,
( u32 ) return_obj . length ) ;
acpi_db_dump_external_object ( return_obj . pointer , 1 ) ;
/* Dump a _PLD buffer if present */
if ( ACPI_COMPARE_NAME
( ( ACPI_CAST_PTR
( struct acpi_namespace_node ,
acpi_gbl_db_method_info . method ) - > name . ascii ) ,
METHOD_NAME__PLD ) ) {
acpi_db_dump_pld_buffer ( return_obj . pointer ) ;
}
} else {
acpi_os_printf
( " No object was returned from evaluation of %s \n " ,
acpi_gbl_db_method_info . pathname ) ;
}
}
acpi_db_set_output_destination ( ACPI_DB_CONSOLE_OUTPUT ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_db_method_thread
*
* PARAMETERS : context - Execution info segment
*
* RETURN : None
*
* DESCRIPTION : Debugger execute thread . Waits for a command line , then
* simply dispatches it .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void ACPI_SYSTEM_XFACE acpi_db_method_thread ( void * context )
{
acpi_status status ;
struct acpi_db_method_info * info = context ;
struct acpi_db_method_info local_info ;
u32 i ;
u8 allow ;
struct acpi_buffer return_obj ;
/*
* acpi_gbl_db_method_info . Arguments will be passed as method arguments .
* Prevent acpi_gbl_db_method_info from being modified by multiple threads
* concurrently .
*
* Note : The arguments we are passing are used by the ASL test suite
* ( aslts ) . Do not change them without updating the tests .
*/
( void ) acpi_os_wait_semaphore ( info - > info_gate , 1 , ACPI_WAIT_FOREVER ) ;
if ( info - > init_args ) {
acpi_db_uint32_to_hex_string ( info - > num_created ,
info - > index_of_thread_str ) ;
acpi_db_uint32_to_hex_string ( ( u32 ) acpi_os_get_thread_id ( ) ,
info - > id_of_thread_str ) ;
}
if ( info - > threads & & ( info - > num_created < info - > num_threads ) ) {
info - > threads [ info - > num_created + + ] = acpi_os_get_thread_id ( ) ;
}
local_info = * info ;
local_info . args = local_info . arguments ;
local_info . arguments [ 0 ] = local_info . num_threads_str ;
local_info . arguments [ 1 ] = local_info . id_of_thread_str ;
local_info . arguments [ 2 ] = local_info . index_of_thread_str ;
local_info . arguments [ 3 ] = NULL ;
local_info . types = local_info . arg_types ;
( void ) acpi_os_signal_semaphore ( info - > info_gate , 1 ) ;
for ( i = 0 ; i < info - > num_loops ; i + + ) {
status = acpi_db_execute_method ( & local_info , & return_obj ) ;
if ( ACPI_FAILURE ( status ) ) {
acpi_os_printf
( " %s During evaluation of %s at iteration %X \n " ,
acpi_format_exception ( status ) , info - > pathname , i ) ;
if ( status = = AE_ABORT_METHOD ) {
break ;
}
}
#if 0
if ( ( i % 100 ) = = 0 ) {
acpi_os_printf ( " %u loops, Thread 0x%x \n " ,
i , acpi_os_get_thread_id ( ) ) ;
}
if ( return_obj . length ) {
acpi_os_printf
( " Evaluation of %s returned object %p Buflen %X \n " ,
info - > pathname , return_obj . pointer ,
( u32 ) return_obj . length ) ;
acpi_db_dump_external_object ( return_obj . pointer , 1 ) ;
}
# endif
}
/* Signal our completion */
allow = 0 ;
( void ) acpi_os_wait_semaphore ( info - > thread_complete_gate ,
1 , ACPI_WAIT_FOREVER ) ;
info - > num_completed + + ;
if ( info - > num_completed = = info - > num_threads ) {
/* Do signal for main thread once only */
allow = 1 ;
}
( void ) acpi_os_signal_semaphore ( info - > thread_complete_gate , 1 ) ;
if ( allow ) {
status = acpi_os_signal_semaphore ( info - > main_thread_gate , 1 ) ;
if ( ACPI_FAILURE ( status ) ) {
acpi_os_printf
( " Could not signal debugger thread sync semaphore, %s \n " ,
acpi_format_exception ( status ) ) ;
}
}
}
/*******************************************************************************
*
* FUNCTION : acpi_db_create_execution_threads
*
* PARAMETERS : num_threads_arg - Number of threads to create
* num_loops_arg - Loop count for the thread ( s )
* method_name_arg - Control method to execute
*
* RETURN : None
*
* DESCRIPTION : Create threads to execute method ( s )
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
acpi_db_create_execution_threads ( char * num_threads_arg ,
char * num_loops_arg , char * method_name_arg )
{
acpi_status status ;
u32 num_threads ;
u32 num_loops ;
u32 i ;
u32 size ;
acpi_mutex main_thread_gate ;
acpi_mutex thread_complete_gate ;
acpi_mutex info_gate ;
/* Get the arguments */
num_threads = strtoul ( num_threads_arg , NULL , 0 ) ;
num_loops = strtoul ( num_loops_arg , NULL , 0 ) ;
if ( ! num_threads | | ! num_loops ) {
acpi_os_printf ( " Bad argument: Threads %X, Loops %X \n " ,
num_threads , num_loops ) ;
return ;
}
/*
* Create the semaphore for synchronization of
* the created threads with the main thread .
*/
status = acpi_os_create_semaphore ( 1 , 0 , & main_thread_gate ) ;
if ( ACPI_FAILURE ( status ) ) {
acpi_os_printf ( " Could not create semaphore for "
" synchronization with the main thread, %s \n " ,
acpi_format_exception ( status ) ) ;
return ;
}
/*
* Create the semaphore for synchronization
* between the created threads .
*/
status = acpi_os_create_semaphore ( 1 , 1 , & thread_complete_gate ) ;
if ( ACPI_FAILURE ( status ) ) {
acpi_os_printf ( " Could not create semaphore for "
" synchronization between the created threads, %s \n " ,
acpi_format_exception ( status ) ) ;
( void ) acpi_os_delete_semaphore ( main_thread_gate ) ;
return ;
}
status = acpi_os_create_semaphore ( 1 , 1 , & info_gate ) ;
if ( ACPI_FAILURE ( status ) ) {
acpi_os_printf ( " Could not create semaphore for "
" synchronization of AcpiGbl_DbMethodInfo, %s \n " ,
acpi_format_exception ( status ) ) ;
( void ) acpi_os_delete_semaphore ( thread_complete_gate ) ;
( void ) acpi_os_delete_semaphore ( main_thread_gate ) ;
return ;
}
memset ( & acpi_gbl_db_method_info , 0 , sizeof ( struct acpi_db_method_info ) ) ;
/* Array to store IDs of threads */
acpi_gbl_db_method_info . num_threads = num_threads ;
size = sizeof ( acpi_thread_id ) * acpi_gbl_db_method_info . num_threads ;
acpi_gbl_db_method_info . threads = acpi_os_allocate ( size ) ;
if ( acpi_gbl_db_method_info . threads = = NULL ) {
acpi_os_printf ( " No memory for thread IDs array \n " ) ;
( void ) acpi_os_delete_semaphore ( main_thread_gate ) ;
( void ) acpi_os_delete_semaphore ( thread_complete_gate ) ;
( void ) acpi_os_delete_semaphore ( info_gate ) ;
return ;
}
memset ( acpi_gbl_db_method_info . threads , 0 , size ) ;
/* Setup the context to be passed to each thread */
acpi_gbl_db_method_info . name = method_name_arg ;
acpi_gbl_db_method_info . flags = 0 ;
acpi_gbl_db_method_info . num_loops = num_loops ;
acpi_gbl_db_method_info . main_thread_gate = main_thread_gate ;
acpi_gbl_db_method_info . thread_complete_gate = thread_complete_gate ;
acpi_gbl_db_method_info . info_gate = info_gate ;
/* Init arguments to be passed to method */
acpi_gbl_db_method_info . init_args = 1 ;
acpi_gbl_db_method_info . args = acpi_gbl_db_method_info . arguments ;
acpi_gbl_db_method_info . arguments [ 0 ] =
acpi_gbl_db_method_info . num_threads_str ;
acpi_gbl_db_method_info . arguments [ 1 ] =
acpi_gbl_db_method_info . id_of_thread_str ;
acpi_gbl_db_method_info . arguments [ 2 ] =
acpi_gbl_db_method_info . index_of_thread_str ;
acpi_gbl_db_method_info . arguments [ 3 ] = NULL ;
acpi_gbl_db_method_info . types = acpi_gbl_db_method_info . arg_types ;
acpi_gbl_db_method_info . arg_types [ 0 ] = ACPI_TYPE_INTEGER ;
acpi_gbl_db_method_info . arg_types [ 1 ] = ACPI_TYPE_INTEGER ;
acpi_gbl_db_method_info . arg_types [ 2 ] = ACPI_TYPE_INTEGER ;
acpi_db_uint32_to_hex_string ( num_threads ,
acpi_gbl_db_method_info . num_threads_str ) ;
status = acpi_db_execute_setup ( & acpi_gbl_db_method_info ) ;
if ( ACPI_FAILURE ( status ) ) {
goto cleanup_and_exit ;
}
/* Get the NS node, determines existence also */
status = acpi_get_handle ( NULL , acpi_gbl_db_method_info . pathname ,
& acpi_gbl_db_method_info . method ) ;
if ( ACPI_FAILURE ( status ) ) {
acpi_os_printf ( " %s Could not get handle for %s \n " ,
acpi_format_exception ( status ) ,
acpi_gbl_db_method_info . pathname ) ;
goto cleanup_and_exit ;
}
/* Create the threads */
acpi_os_printf ( " Creating %X threads to execute %X times each \n " ,
num_threads , num_loops ) ;
for ( i = 0 ; i < ( num_threads ) ; i + + ) {
status =
2015-10-19 05:25:50 +03:00
acpi_os_execute ( OSL_DEBUGGER_EXEC_THREAD ,
acpi_db_method_thread ,
2015-10-19 05:25:20 +03:00
& acpi_gbl_db_method_info ) ;
if ( ACPI_FAILURE ( status ) ) {
break ;
}
}
/* Wait for all threads to complete */
( void ) acpi_os_wait_semaphore ( main_thread_gate , 1 , ACPI_WAIT_FOREVER ) ;
acpi_db_set_output_destination ( ACPI_DB_DUPLICATE_OUTPUT ) ;
acpi_os_printf ( " All threads (%X) have completed \n " , num_threads ) ;
acpi_db_set_output_destination ( ACPI_DB_CONSOLE_OUTPUT ) ;
cleanup_and_exit :
/* Cleanup and exit */
( void ) acpi_os_delete_semaphore ( main_thread_gate ) ;
( void ) acpi_os_delete_semaphore ( thread_complete_gate ) ;
( void ) acpi_os_delete_semaphore ( info_gate ) ;
acpi_os_free ( acpi_gbl_db_method_info . threads ) ;
acpi_gbl_db_method_info . threads = NULL ;
}