/******************************************************************************* * * FUNCTION: acpi_terminate_debugger * * PARAMETERS: None * * RETURN: None * * DESCRIPTION: Stop debugger * ******************************************************************************/ void acpi_terminate_debugger(void) { /* Terminate the AML Debugger */ acpi_gbl_db_terminate_loop = TRUE; if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { acpi_os_release_mutex(acpi_gbl_db_command_ready); /* Wait the AML Debugger threads */ while (!acpi_gbl_db_threads_terminated) { acpi_os_sleep(100); } } if (acpi_gbl_db_buffer) { acpi_os_free(acpi_gbl_db_buffer); acpi_gbl_db_buffer = NULL; } /* Ensure that debug output is now disabled */ acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT; }
acpi_status acpi_ut_osi_implementation(struct acpi_walk_state * walk_state) { union acpi_operand_object *string_desc; union acpi_operand_object *return_desc; struct acpi_interface_info *interface_info; acpi_interface_handler interface_handler; u32 return_value; ACPI_FUNCTION_TRACE(ut_osi_implementation); string_desc = walk_state->arguments[0].object; if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) { return_ACPI_STATUS(AE_TYPE); } return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); if (!return_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } return_value = 0; (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); interface_info = acpi_ut_get_interface(string_desc->string.pointer); if (interface_info && !(interface_info->flags & ACPI_OSI_INVALID)) { if (interface_info->value > acpi_gbl_osi_data) { acpi_gbl_osi_data = interface_info->value; } return_value = ACPI_UINT32_MAX; } acpi_os_release_mutex(acpi_gbl_osi_mutex); interface_handler = acpi_gbl_interface_handler; if (interface_handler) { return_value = interface_handler(string_desc->string.pointer, return_value); } ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, "ACPI: BIOS _OSI(\"%s\") is %ssupported\n", string_desc->string.pointer, return_value == 0 ? "not " : "")); return_desc->integer.value = return_value; walk_state->return_desc = return_desc; return_ACPI_STATUS(AE_OK); }
acpi_status acpi_ut_interface_terminate(void) { acpi_status status; struct acpi_interface_info *next_interface; status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); if (ACPI_FAILURE(status)) { return (status); } next_interface = acpi_gbl_supported_interfaces; while (next_interface) { acpi_gbl_supported_interfaces = next_interface->next; /* Only interfaces added at runtime can be freed */ if (next_interface->flags & ACPI_OSI_DYNAMIC) { ACPI_FREE(next_interface->name); ACPI_FREE(next_interface); } next_interface = acpi_gbl_supported_interfaces; } acpi_os_release_mutex(acpi_gbl_osi_mutex); return (AE_OK); }
acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) { acpi_thread_id this_thread_id; ACPI_FUNCTION_NAME(ut_release_mutex); this_thread_id = acpi_os_get_thread_id(); ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %X releasing Mutex [%s]\n", (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id))); if (mutex_id > ACPI_MAX_MUTEX) { return (AE_BAD_PARAMETER); } /* * Mutex must be acquired in order to release it! */ if (acpi_gbl_mutex_info[mutex_id].thread_id == ACPI_MUTEX_NOT_ACQUIRED) { ACPI_ERROR((AE_INFO, "Mutex [%X] is not acquired, cannot release", mutex_id)); return (AE_NOT_ACQUIRED); } #ifdef ACPI_MUTEX_DEBUG { u32 i; /* * Mutex debug code, for internal debugging only. * * Deadlock prevention. Check if this thread owns any mutexes of value * greater than this one. If so, the thread has violated the mutex * ordering rule. This indicates a coding error somewhere in * the ACPI subsystem code. */ for (i = mutex_id; i < ACPI_MAX_MUTEX; i++) { if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { if (i == mutex_id) { continue; } ACPI_ERROR((AE_INFO, "Invalid release order: owns [%s], releasing [%s]", acpi_ut_get_mutex_name(i), acpi_ut_get_mutex_name(mutex_id))); return (AE_RELEASE_DEADLOCK); } } } #endif /* Mark unlocked FIRST */ acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED; acpi_os_release_mutex(acpi_gbl_mutex_info[mutex_id].mutex); return (AE_OK); }
acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op) { acpi_status status = AE_OK; acpi_os_printf("\n"); /* TBD: [Restructure] Need a separate command line buffer for step mode */ while (!acpi_gbl_db_terminate_loop) { /* Force output to console until a command is entered */ acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); /* Different prompt if method is executing */ if (!acpi_gbl_method_executing) { acpi_os_printf("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); } else { acpi_os_printf("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); } /* Get the user input line */ status = acpi_os_get_line(acpi_gbl_db_line_buf, ACPI_DB_LINE_BUFFER_SIZE, NULL); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "While parsing command line")); return (status); } /* Check for single or multithreaded debug */ if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { /* * Signal the debug thread that we have a command to execute, * and wait for the command to complete. */ acpi_os_release_mutex(acpi_gbl_db_command_ready); if (ACPI_FAILURE(status)) { return (status); } status = acpi_os_acquire_mutex(acpi_gbl_db_command_complete, ACPI_WAIT_FOREVER); if (ACPI_FAILURE(status)) { return (status); } } else { /* Just call to the command line interpreter */ acpi_db_single_thread(); } } return (status); }
acpi_status acpi_ut_release_read_lock(struct acpi_rw_lock *lock) { acpi_status status; status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER); if (ACPI_FAILURE(status)) { return status; } /* Release the write lock only for the very last reader */ lock->num_readers--; if (lock->num_readers == 0) { acpi_os_release_mutex(lock->writer_mutex); } acpi_os_release_mutex(lock->reader_mutex); return status; }
/***************************************************************************** * * FUNCTION: acpi_update_interfaces * * PARAMETERS: action - Actions to be performed during the * update * * RETURN: Status * * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor * string or/and feature group strings. * ****************************************************************************/ acpi_status acpi_update_interfaces(u8 action) { acpi_status status; status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); if (ACPI_FAILURE(status)) { return (status); } status = acpi_ut_update_interfaces(action); acpi_os_release_mutex(acpi_gbl_osi_mutex); return (status); }
acpi_status acpi_ev_release_global_lock(void) { u8 pending = FALSE; acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(ev_release_global_lock); /* Lock must be already acquired */ if (!acpi_gbl_global_lock_acquired) { ACPI_WARNING((AE_INFO, "Cannot release the ACPI Global Lock, it has not been acquired")); return_ACPI_STATUS(AE_NOT_ACQUIRED); } acpi_ev_global_lock_acquired--; if (acpi_ev_global_lock_acquired > 0) { return AE_OK; } if (acpi_gbl_global_lock_present) { /* Allow any thread to release the lock */ ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending); /* * If the pending bit was set, we must write GBL_RLS to the control * register */ if (pending) { status = acpi_write_bit_register (ACPI_BITREG_GLOBAL_LOCK_RELEASE, ACPI_ENABLE_EVENT); } ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Released hardware Global Lock\n")); } acpi_gbl_global_lock_acquired = FALSE; /* Release the local GL mutex */ acpi_ev_global_lock_thread_id = 0; acpi_ev_global_lock_acquired = 0; acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex); return_ACPI_STATUS(status); }
/***************************************************************************** * * FUNCTION: acpi_install_interface_handler * * PARAMETERS: Handler - The _OSI interface handler to install * NULL means "remove existing handler" * * RETURN: Status * * DESCRIPTION: Install a handler for the predefined _OSI ACPI method. * invoked during execution of the internal implementation of * _OSI. A NULL handler simply removes any existing handler. * ****************************************************************************/ acpi_status acpi_install_interface_handler(acpi_interface_handler handler) { acpi_status status = AE_OK; (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); if (handler && acpi_gbl_interface_handler) { status = AE_ALREADY_EXISTS; } else { acpi_gbl_interface_handler = handler; } acpi_os_release_mutex(acpi_gbl_osi_mutex); return (status); }
/******************************************************************************* * * FUNCTION: acpi_release_mutex * * PARAMETERS: handle - Mutex or prefix handle (optional) * pathname - Mutex pathname (optional) * * RETURN: Status * * DESCRIPTION: Release an AML mutex. This is a device driver interface to * AML mutex objects, and allows for transaction locking between * drivers and AML code. The mutex node is pointed to by * Handle:Pathname. Either Handle or Pathname can be NULL, but * not both. * ******************************************************************************/ acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname) { acpi_status status; union acpi_operand_object *mutex_obj; /* Get the low-level mutex associated with Handle:Pathname */ status = acpi_ut_get_mutex_object(handle, pathname, &mutex_obj); if (ACPI_FAILURE(status)) { return (status); } /* Release the OS mutex */ acpi_os_release_mutex(mutex_obj->mutex.os_mutex); return (AE_OK); }
/***************************************************************************** * * FUNCTION: acpi_remove_interface * * PARAMETERS: interface_name - The interface to remove * * RETURN: Status * * DESCRIPTION: Remove an _OSI interface from the global list * ****************************************************************************/ acpi_status acpi_remove_interface(acpi_string interface_name) { acpi_status status; /* Parameter validation */ if (!interface_name || (ACPI_STRLEN(interface_name) == 0)) { return (AE_BAD_PARAMETER); } (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); status = acpi_ut_remove_interface(interface_name); acpi_os_release_mutex(acpi_gbl_osi_mutex); return (status); }
void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) { union acpi_operand_object *next = thread->acquired_mutex_list; union acpi_operand_object *obj_desc; ACPI_FUNCTION_TRACE(ex_release_all_mutexes); /* Traverse the list of owned mutexes, releasing each one */ while (next) { obj_desc = next; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Mutex [%4.4s] force-release, SyncLevel %u Depth %u\n", obj_desc->mutex.node->name.ascii, obj_desc->mutex.sync_level, obj_desc->mutex.acquisition_depth)); /* Release the mutex, special case for Global Lock */ if (obj_desc == acpi_gbl_global_lock_mutex) { /* Ignore errors */ (void)acpi_ev_release_global_lock(); } else { acpi_os_release_mutex(obj_desc->mutex.os_mutex); } /* Update Thread sync_level (Last mutex is the important one) */ thread->current_sync_level = obj_desc->mutex.original_sync_level; /* Mark mutex unowned */ next = obj_desc->mutex.next; obj_desc->mutex.prev = NULL; obj_desc->mutex.next = NULL; obj_desc->mutex.acquisition_depth = 0; obj_desc->mutex.owner_thread = NULL; obj_desc->mutex.thread_id = 0; } return_VOID; }
acpi_status acpi_ut_initialize_interfaces(void) { u32 i; (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); acpi_gbl_supported_interfaces = acpi_default_supported_interfaces; /* Link the static list of supported interfaces */ for (i = 0; i < (ACPI_ARRAY_LENGTH(acpi_default_supported_interfaces) - 1); i++) { acpi_default_supported_interfaces[i].next = &acpi_default_supported_interfaces[(acpi_size) i + 1]; } acpi_os_release_mutex(acpi_gbl_osi_mutex); return (AE_OK); }
acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc) { acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(ex_system_release_mutex); if (!obj_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Support for the _GL_ Mutex object -- release the global lock */ if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) { status = acpi_ev_release_global_lock(); return_ACPI_STATUS(status); } acpi_os_release_mutex(obj_desc->mutex.os_mutex); return_ACPI_STATUS(AE_OK); }
acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc) { acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(ex_release_mutex_object); if (obj_desc->mutex.acquisition_depth == 0) { return (AE_NOT_ACQUIRED); } /* Match multiple Acquires with multiple Releases */ obj_desc->mutex.acquisition_depth--; if (obj_desc->mutex.acquisition_depth != 0) { /* Just decrement the depth and return */ return_ACPI_STATUS(AE_OK); } if (obj_desc->mutex.owner_thread) { /* Unlink the mutex from the owner's list */ acpi_ex_unlink_mutex(obj_desc); obj_desc->mutex.owner_thread = NULL; } /* Release the mutex, special case for Global Lock */ if (obj_desc == acpi_gbl_global_lock_mutex) { status = acpi_ev_release_global_lock(); } else { acpi_os_release_mutex(obj_desc->mutex.os_mutex); } /* Clear mutex info */ obj_desc->mutex.thread_id = NULL; return_ACPI_STATUS(status); }
acpi_status acpi_ut_acquire_read_lock(struct acpi_rw_lock *lock) { acpi_status status; status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER); if (ACPI_FAILURE(status)) { return (status); } /* Acquire the write lock only for the first reader */ lock->num_readers++; if (lock->num_readers == 1) { status = acpi_os_acquire_mutex(lock->writer_mutex, ACPI_WAIT_FOREVER); } acpi_os_release_mutex(lock->reader_mutex); return (status); }
void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context) { acpi_status status = AE_OK; acpi_status Mstatus; while (status != AE_CTRL_TERMINATE && !acpi_gbl_db_terminate_loop) { acpi_gbl_method_executing = FALSE; acpi_gbl_step_to_next_call = FALSE; Mstatus = acpi_os_acquire_mutex(acpi_gbl_db_command_ready, ACPI_WAIT_FOREVER); if (ACPI_FAILURE(Mstatus)) { return; } status = acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, NULL); acpi_os_release_mutex(acpi_gbl_db_command_complete); } acpi_gbl_db_threads_terminated = TRUE; }
/***************************************************************************** * * FUNCTION: acpi_install_interface * * PARAMETERS: interface_name - The interface to install * * RETURN: Status * * DESCRIPTION: Install an _OSI interface to the global list * ****************************************************************************/ acpi_status acpi_install_interface(acpi_string interface_name) { acpi_status status; struct acpi_interface_info *interface_info; /* Parameter validation */ if (!interface_name || (strlen(interface_name) == 0)) { return (AE_BAD_PARAMETER); } status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); if (ACPI_FAILURE(status)) { return (status); } /* Check if the interface name is already in the global list */ interface_info = acpi_ut_get_interface(interface_name); if (interface_info) { /* * The interface already exists in the list. This is OK if the * interface has been marked invalid -- just clear the bit. */ if (interface_info->flags & ACPI_OSI_INVALID) { interface_info->flags &= ~ACPI_OSI_INVALID; status = AE_OK; } else { status = AE_ALREADY_EXISTS; } } else { /* New interface name, install into the global list */ status = acpi_ut_install_interface(interface_name); } acpi_os_release_mutex(acpi_gbl_osi_mutex); return (status); }
void acpi_ut_interface_terminate(void) { struct acpi_interface_info *next_interface; (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); next_interface = acpi_gbl_supported_interfaces; while (next_interface) { acpi_gbl_supported_interfaces = next_interface->next; /* Only interfaces added at runtime can be freed */ if (next_interface->flags & ACPI_OSI_DYNAMIC) { ACPI_FREE(next_interface->name); ACPI_FREE(next_interface); } next_interface = acpi_gbl_supported_interfaces; } acpi_os_release_mutex(acpi_gbl_osi_mutex); }
acpi_status acpi_ev_release_global_lock(void) { u8 pending = FALSE; acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(ev_release_global_lock); if (!acpi_gbl_global_lock_acquired) { ACPI_WARNING((AE_INFO, "Cannot release the ACPI Global Lock, it has not been acquired")); return_ACPI_STATUS(AE_NOT_ACQUIRED); } if (acpi_gbl_global_lock_present) { ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending); if (pending) { status = acpi_write_bit_register (ACPI_BITREG_GLOBAL_LOCK_RELEASE, ACPI_ENABLE_EVENT); } ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Released hardware Global Lock\n")); } acpi_gbl_global_lock_acquired = FALSE; acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex); return_ACPI_STATUS(status); }
void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) { union acpi_operand_object *next = thread->acquired_mutex_list; union acpi_operand_object *obj_desc; ACPI_FUNCTION_ENTRY(); /* Traverse the list of owned mutexes, releasing each one */ while (next) { obj_desc = next; next = obj_desc->mutex.next; obj_desc->mutex.prev = NULL; obj_desc->mutex.next = NULL; obj_desc->mutex.acquisition_depth = 0; /* Release the mutex, special case for Global Lock */ if (obj_desc == acpi_gbl_global_lock_mutex) { /* Ignore errors */ (void)acpi_ev_release_global_lock(); } else { acpi_os_release_mutex(obj_desc->mutex.os_mutex); } /* Mark mutex unowned */ obj_desc->mutex.owner_thread = NULL; obj_desc->mutex.thread_id = NULL; /* Update Thread sync_level (Last mutex is the important one) */ thread->current_sync_level = obj_desc->mutex.original_sync_level; } }
acpi_status acpi_ut_interface_terminate(void) { acpi_status status; struct acpi_interface_info *next_interface; status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); if (ACPI_FAILURE(status)) { return (status); } next_interface = acpi_gbl_supported_interfaces; while (next_interface) { acpi_gbl_supported_interfaces = next_interface->next; if (next_interface->flags & ACPI_OSI_DYNAMIC) { /* Only interfaces added at runtime can be freed */ ACPI_FREE(next_interface->name); ACPI_FREE(next_interface); } else { /* Interface is in static list. Reset it to invalid or valid. */ if (next_interface->flags & ACPI_OSI_DEFAULT_INVALID) { next_interface->flags |= ACPI_OSI_INVALID; } else { next_interface->flags &= ~ACPI_OSI_INVALID; } } next_interface = acpi_gbl_supported_interfaces; } acpi_os_release_mutex(acpi_gbl_osi_mutex); return (AE_OK); }
acpi_status acpi_ut_osi_implementation(struct acpi_walk_state * walk_state) { union acpi_operand_object *string_desc; union acpi_operand_object *return_desc; struct acpi_interface_info *interface_info; acpi_interface_handler interface_handler; acpi_status status; u32 return_value; ACPI_FUNCTION_TRACE(ut_osi_implementation); /* Validate the string input argument (from the AML caller) */ string_desc = walk_state->arguments[0].object; if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) { return_ACPI_STATUS(AE_TYPE); } /* Create a return object */ return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); if (!return_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Default return value is 0, NOT SUPPORTED */ return_value = 0; status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(return_desc); return_ACPI_STATUS(status); } /* Lookup the interface in the global _OSI list */ interface_info = acpi_ut_get_interface(string_desc->string.pointer); if (interface_info && !(interface_info->flags & ACPI_OSI_INVALID)) { /* * The interface is supported. * Update the osi_data if necessary. We keep track of the latest * version of Windows that has been requested by the BIOS. */ if (interface_info->value > acpi_gbl_osi_data) { acpi_gbl_osi_data = interface_info->value; } return_value = ACPI_UINT32_MAX; } acpi_os_release_mutex(acpi_gbl_osi_mutex); /* * Invoke an optional _OSI interface handler. The host OS may wish * to do some interface-specific handling. For example, warn about * certain interfaces or override the true/false support value. */ interface_handler = acpi_gbl_interface_handler; if (interface_handler) { return_value = interface_handler(string_desc->string.pointer, return_value); } ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, "ACPI: BIOS _OSI(\"%s\") is %ssupported\n", string_desc->string.pointer, return_value == 0 ? "not " : "")); /* Complete the return object */ return_desc->integer.value = return_value; walk_state->return_desc = return_desc; return_ACPI_STATUS(AE_OK); }
static acpi_status acpi_db_start_command(struct acpi_walk_state *walk_state, union acpi_parse_object *op) { acpi_status status; /* TBD: [Investigate] are there namespace locking issues here? */ /* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */ /* Go into the command loop and await next user command */ acpi_gbl_method_executing = TRUE; status = AE_CTRL_TRUE; while (status == AE_CTRL_TRUE) { if (acpi_gbl_debugger_configuration == DEBUGGER_MULTI_THREADED) { /* Handshake with the front-end that gets user command lines */ acpi_os_release_mutex(acpi_gbl_db_command_complete); status = acpi_os_acquire_mutex(acpi_gbl_db_command_ready, ACPI_WAIT_FOREVER); if (ACPI_FAILURE(status)) { return (status); } } else { /* Single threaded, we must get a command line ourselves */ /* Force output to console until a command is entered */ acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); /* Different prompt if method is executing */ if (!acpi_gbl_method_executing) { acpi_os_printf("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); } else { acpi_os_printf("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); } /* Get the user input line */ status = acpi_os_get_line(acpi_gbl_db_line_buf, ACPI_DB_LINE_BUFFER_SIZE, NULL); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "While parsing command line")); return (status); } } status = acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state, op); } /* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */ return (status); }
acpi_status acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node); if (!method_node) { return_ACPI_STATUS(AE_NULL_ENTRY); } /* Prevent wraparound of thread count */ if (obj_desc->method.thread_count == ACPI_UINT8_MAX) { ACPI_ERROR((AE_INFO, "Method reached maximum reentrancy limit (255)")); return_ACPI_STATUS(AE_AML_METHOD_LIMIT); } /* * If this method is serialized, we need to acquire the method mutex. */ if (obj_desc->method.method_flags & AML_METHOD_SERIALIZED) { /* * Create a mutex for the method if it is defined to be Serialized * and a mutex has not already been created. We defer the mutex creation * until a method is actually executed, to minimize the object count */ if (!obj_desc->method.mutex) { status = acpi_ds_create_method_mutex(obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } /* * The current_sync_level (per-thread) must be less than or equal to * the sync level of the method. This mechanism provides some * deadlock prevention * * Top-level method invocation has no walk state at this point */ if (walk_state && (walk_state->thread->current_sync_level > obj_desc->method.mutex->mutex.sync_level)) { ACPI_ERROR((AE_INFO, "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%d)", acpi_ut_get_node_name(method_node), walk_state->thread->current_sync_level)); return_ACPI_STATUS(AE_AML_MUTEX_ORDER); } /* * Obtain the method mutex if necessary. Do not acquire mutex for a * recursive call. */ if (acpi_os_get_thread_id() != obj_desc->method.mutex->mutex.owner_thread_id) { /* * Acquire the method mutex. This releases the interpreter if we * block (and reacquires it before it returns) */ status = acpi_ex_system_wait_mutex(obj_desc->method.mutex-> mutex.os_mutex, ACPI_WAIT_FOREVER); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Update the mutex and walk info and save the original sync_level */ obj_desc->method.mutex->mutex.owner_thread_id = acpi_os_get_thread_id(); if (walk_state) { obj_desc->method.mutex->mutex. original_sync_level = walk_state->thread->current_sync_level; walk_state->thread->current_sync_level = obj_desc->method.sync_level; } else { obj_desc->method.mutex->mutex. original_sync_level = obj_desc->method.mutex->mutex.sync_level; } } /* Always increase acquisition depth */ obj_desc->method.mutex->mutex.acquisition_depth++; } /* * Allocate an Owner ID for this method, only if this is the first thread * to begin concurrent execution. We only need one owner_id, even if the * method is invoked recursively. */ if (!obj_desc->method.owner_id) { status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id); if (ACPI_FAILURE(status)) { goto cleanup; } } /* * Increment the method parse tree thread count since it has been * reentered one more time (even if it is the same thread) */ obj_desc->method.thread_count++; return_ACPI_STATUS(status); cleanup: /* On error, must release the method mutex (if present) */ if (obj_desc->method.mutex) { acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex); } return_ACPI_STATUS(status); }
void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg) { struct acpi_interface_info *next_interface; char *sub_string; acpi_status status; /* If no arguments, just display current interface list */ if (!action_arg) { (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); next_interface = acpi_gbl_supported_interfaces; while (next_interface) { if (!(next_interface->flags & ACPI_OSI_INVALID)) { acpi_os_printf("%s\n", next_interface->name); } next_interface = next_interface->next; } acpi_os_release_mutex(acpi_gbl_osi_mutex); return; } /* If action_arg exists, so must interface_name_arg */ if (!interface_name_arg) { acpi_os_printf("Missing Interface Name argument\n"); return; } /* Uppercase the action for match below */ acpi_ut_strupr(action_arg); /* install - install an interface */ sub_string = strstr("INSTALL", action_arg); if (sub_string) { status = acpi_install_interface(interface_name_arg); if (ACPI_FAILURE(status)) { acpi_os_printf("%s, while installing \"%s\"\n", acpi_format_exception(status), interface_name_arg); } return; } /* remove - remove an interface */ sub_string = strstr("REMOVE", action_arg); if (sub_string) { status = acpi_remove_interface(interface_name_arg); if (ACPI_FAILURE(status)) { acpi_os_printf("%s, while removing \"%s\"\n", acpi_format_exception(status), interface_name_arg); } return; } /* Invalid action_arg */ acpi_os_printf("Invalid action argument: %s\n", action_arg); return; }
void acpi_ut_release_write_lock(struct acpi_rw_lock *lock) { acpi_os_release_mutex(lock->writer_mutex); }
void acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, struct acpi_walk_state *walk_state) { ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); /* method_desc is required, walk_state is optional */ if (!method_desc) { return_VOID; } if (walk_state) { /* Delete all arguments and locals */ acpi_ds_method_data_delete_all(walk_state); /* * If method is serialized, release the mutex and restore the * current sync level for this thread */ if (method_desc->method.mutex) { /* Acquisition Depth handles recursive calls */ method_desc->method.mutex->mutex.acquisition_depth--; if (!method_desc->method.mutex->mutex.acquisition_depth) { walk_state->thread->current_sync_level = method_desc->method.mutex->mutex. original_sync_level; acpi_os_release_mutex(method_desc->method. mutex->mutex.os_mutex); method_desc->method.mutex->mutex.thread_id = 0; } } /* * Delete any namespace objects created anywhere within the * namespace by the execution of this method. Unless: * 1) This method is a module-level executable code method, in which * case we want make the objects permanent. * 2) There are other threads executing the method, in which case we * will wait until the last thread has completed. */ if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) && (method_desc->method.thread_count == 1)) { /* Delete any direct children of (created by) this method */ acpi_ns_delete_namespace_subtree(walk_state-> method_node); /* * Delete any objects that were created by this method * elsewhere in the namespace (if any were created). * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the * deletion such that we don't have to perform an entire * namespace walk for every control method execution. */ if (method_desc->method. info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) { acpi_ns_delete_namespace_by_owner(method_desc-> method. owner_id); method_desc->method.info_flags &= ~ACPI_METHOD_MODIFIED_NAMESPACE; } } } /* Decrement the thread count on the method */ if (method_desc->method.thread_count) { method_desc->method.thread_count--; } else { ACPI_ERROR((AE_INFO, "Invalid zero thread count in method")); } /* Are there any other threads currently executing this method? */ if (method_desc->method.thread_count) { /* * Additional threads. Do not release the owner_id in this case, * we immediately reuse it for the next thread executing this method */ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "*** Completed execution of one thread, %u threads remaining\n", method_desc->method.thread_count)); } else { /* This is the only executing thread for this method */ /* * Support to dynamically change a method from not_serialized to * Serialized if it appears that the method is incorrectly written and * does not support multiple thread execution. The best example of this * is if such a method creates namespace objects and blocks. A second * thread will fail with an AE_ALREADY_EXISTS exception. * * This code is here because we must wait until the last thread exits * before marking the method as serialized. */ if (method_desc->method. info_flags & ACPI_METHOD_SERIALIZED_PENDING) { if (walk_state) { ACPI_INFO((AE_INFO, "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", walk_state->method_node->name. ascii)); } /* * Method tried to create an object twice and was marked as * "pending serialized". The probable cause is that the method * cannot handle reentrancy. * * The method was created as not_serialized, but it tried to create * a named object and then blocked, causing the second thread * entrance to begin and then fail. Workaround this problem by * marking the method permanently as Serialized when the last * thread exits here. */ method_desc->method.info_flags &= ~ACPI_METHOD_SERIALIZED_PENDING; method_desc->method.info_flags |= (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); method_desc->method.sync_level = 0; } /* No more threads, we can free the owner_id */ if (! (method_desc->method. info_flags & ACPI_METHOD_MODULE_LEVEL)) { acpi_ut_release_owner_id(&method_desc->method.owner_id); } } return_VOID; }
void acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, struct acpi_walk_state *walk_state) { struct acpi_namespace_node *method_node; acpi_status status; ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); /* method_desc is required, walk_state is optional */ if (!method_desc) { return_VOID; } if (walk_state) { /* Delete all arguments and locals */ acpi_ds_method_data_delete_all(walk_state); } /* * If method is serialized, release the mutex and restore the * current sync level for this thread */ if (method_desc->method.mutex) { /* Acquisition Depth handles recursive calls */ method_desc->method.mutex->mutex.acquisition_depth--; if (!method_desc->method.mutex->mutex.acquisition_depth) { walk_state->thread->current_sync_level = method_desc->method.mutex->mutex. original_sync_level; acpi_os_release_mutex(method_desc->method.mutex->mutex. os_mutex); method_desc->method.mutex->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; } } if (walk_state) { /* * Delete any objects created by this method during execution. * The method Node is stored in the walk state */ method_node = walk_state->method_node; /* * Delete any namespace objects created anywhere within * the namespace by the execution of this method */ acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id); } /* Decrement the thread count on the method */ if (method_desc->method.thread_count) { method_desc->method.thread_count--; } else { ACPI_ERROR((AE_INFO, "Invalid zero thread count in method")); } /* Are there any other threads currently executing this method? */ if (method_desc->method.thread_count) { /* * Additional threads. Do not release the owner_id in this case, * we immediately reuse it for the next thread executing this method */ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "*** Completed execution of one thread, %d threads remaining\n", method_desc->method.thread_count)); } else { /* This is the only executing thread for this method */ /* * Support to dynamically change a method from not_serialized to * Serialized if it appears that the method is incorrectly written and * does not support multiple thread execution. The best example of this * is if such a method creates namespace objects and blocks. A second * thread will fail with an AE_ALREADY_EXISTS exception * * This code is here because we must wait until the last thread exits * before creating the synchronization semaphore. */ if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED) && (!method_desc->method.mutex)) { status = acpi_ds_create_method_mutex(method_desc); } /* No more threads, we can free the owner_id */ acpi_ut_release_owner_id(&method_desc->method.owner_id); } return_VOID; }
acpi_status acpi_ex_release_mutex(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(ex_release_mutex); if (!obj_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* The mutex must have been previously acquired in order to release it */ if (!obj_desc->mutex.owner_thread_id) { ACPI_ERROR((AE_INFO, "Cannot release Mutex [%4.4s], not acquired", acpi_ut_get_node_name(obj_desc->mutex.node))); return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); } /* Sanity check: we must have a valid thread ID */ if (!walk_state->thread) { ACPI_ERROR((AE_INFO, "Cannot release Mutex [%4.4s], null thread info", acpi_ut_get_node_name(obj_desc->mutex.node))); return_ACPI_STATUS(AE_AML_INTERNAL); } /* * The Mutex is owned, but this thread must be the owner. * Special case for Global Lock, any thread can release */ if ((obj_desc->mutex.owner_thread_id != walk_state->thread->thread_id) && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) { ACPI_ERROR((AE_INFO, "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", (unsigned long)walk_state->thread->thread_id, acpi_ut_get_node_name(obj_desc->mutex.node), (unsigned long)obj_desc->mutex.owner_thread_id)); return_ACPI_STATUS(AE_AML_NOT_OWNER); } /* * The sync level of the mutex must be less than or equal to the current * sync level */ if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { ACPI_ERROR((AE_INFO, "Cannot release Mutex [%4.4s], incorrect SyncLevel", acpi_ut_get_node_name(obj_desc->mutex.node))); return_ACPI_STATUS(AE_AML_MUTEX_ORDER); } /* Match multiple Acquires with multiple Releases */ obj_desc->mutex.acquisition_depth--; if (obj_desc->mutex.acquisition_depth != 0) { /* Just decrement the depth and return */ return_ACPI_STATUS(AE_OK); } /* Unlink the mutex from the owner's list */ acpi_ex_unlink_mutex(obj_desc, walk_state->thread); /* Release the mutex, special case for Global Lock */ if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) { status = acpi_ev_release_global_lock(); } else { acpi_os_release_mutex(obj_desc->mutex.os_mutex); } /* Update the mutex and restore sync_level */ obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; walk_state->thread->current_sync_level = obj_desc->mutex.original_sync_level; return_ACPI_STATUS(status); }