|
@@ -359,19 +359,20 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list)
|
|
|
* FUNCTION: acpi_ut_update_ref_count
|
|
|
*
|
|
|
* PARAMETERS: object - Object whose ref count is to be updated
|
|
|
- * action - What to do
|
|
|
+ * action - What to do (REF_INCREMENT or REF_DECREMENT)
|
|
|
*
|
|
|
- * RETURN: New ref count
|
|
|
+ * RETURN: None. Sets new reference count within the object
|
|
|
*
|
|
|
- * DESCRIPTION: Modify the ref count and return it.
|
|
|
+ * DESCRIPTION: Modify the reference count for an internal acpi object
|
|
|
*
|
|
|
******************************************************************************/
|
|
|
|
|
|
static void
|
|
|
acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
|
|
|
{
|
|
|
- u16 count;
|
|
|
- u16 new_count;
|
|
|
+ u16 original_count;
|
|
|
+ u16 new_count = 0;
|
|
|
+ acpi_cpu_flags lock_flags;
|
|
|
|
|
|
ACPI_FUNCTION_NAME(ut_update_ref_count);
|
|
|
|
|
@@ -379,46 +380,58 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- count = object->common.reference_count;
|
|
|
- new_count = count;
|
|
|
-
|
|
|
/*
|
|
|
- * Perform the reference count action (increment, decrement, force delete)
|
|
|
+ * Always get the reference count lock. Note: Interpreter and/or
|
|
|
+ * Namespace is not always locked when this function is called.
|
|
|
*/
|
|
|
+ lock_flags = acpi_os_acquire_lock(acpi_gbl_reference_count_lock);
|
|
|
+ original_count = object->common.reference_count;
|
|
|
+
|
|
|
+ /* Perform the reference count action (increment, decrement) */
|
|
|
+
|
|
|
switch (action) {
|
|
|
case REF_INCREMENT:
|
|
|
|
|
|
- new_count++;
|
|
|
+ new_count = original_count + 1;
|
|
|
object->common.reference_count = new_count;
|
|
|
+ acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
|
|
|
+
|
|
|
+ /* The current reference count should never be zero here */
|
|
|
+
|
|
|
+ if (!original_count) {
|
|
|
+ ACPI_WARNING((AE_INFO,
|
|
|
+ "Obj %p, Reference Count was zero before increment\n",
|
|
|
+ object));
|
|
|
+ }
|
|
|
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
|
|
|
- "Obj %p Refs=%X, [Incremented]\n",
|
|
|
- object, new_count));
|
|
|
+ "Obj %p Type %.2X Refs %.2X [Incremented]\n",
|
|
|
+ object, object->common.type, new_count));
|
|
|
break;
|
|
|
|
|
|
case REF_DECREMENT:
|
|
|
|
|
|
- if (count < 1) {
|
|
|
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
|
|
|
- "Obj %p Refs=%X, can't decrement! (Set to 0)\n",
|
|
|
- object, new_count));
|
|
|
-
|
|
|
- new_count = 0;
|
|
|
- } else {
|
|
|
- new_count--;
|
|
|
+ /* The current reference count must be non-zero */
|
|
|
|
|
|
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
|
|
|
- "Obj %p Refs=%X, [Decremented]\n",
|
|
|
- object, new_count));
|
|
|
+ if (original_count) {
|
|
|
+ new_count = original_count - 1;
|
|
|
+ object->common.reference_count = new_count;
|
|
|
}
|
|
|
|
|
|
- if (object->common.type == ACPI_TYPE_METHOD) {
|
|
|
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
|
|
|
- "Method Obj %p Refs=%X, [Decremented]\n",
|
|
|
- object, new_count));
|
|
|
+ acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
|
|
|
+
|
|
|
+ if (!original_count) {
|
|
|
+ ACPI_WARNING((AE_INFO,
|
|
|
+ "Obj %p, Reference Count is already zero, cannot decrement\n",
|
|
|
+ object));
|
|
|
}
|
|
|
|
|
|
- object->common.reference_count = new_count;
|
|
|
+ ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
|
|
|
+ "Obj %p Type %.2X Refs %.2X [Decremented]\n",
|
|
|
+ object, object->common.type, new_count));
|
|
|
+
|
|
|
+ /* Actually delete the object on a reference count of zero */
|
|
|
+
|
|
|
if (new_count == 0) {
|
|
|
acpi_ut_delete_internal_obj(object);
|
|
|
}
|
|
@@ -426,18 +439,20 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
|
|
|
|
|
|
default:
|
|
|
|
|
|
- ACPI_ERROR((AE_INFO, "Unknown action (0x%X)", action));
|
|
|
- break;
|
|
|
+ acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
|
|
|
+ ACPI_ERROR((AE_INFO, "Unknown Reference Count action (0x%X)",
|
|
|
+ action));
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* Sanity check the reference count, for debug purposes only.
|
|
|
* (A deleted object will have a huge reference count)
|
|
|
*/
|
|
|
- if (count > ACPI_MAX_REFERENCE_COUNT) {
|
|
|
+ if (new_count > ACPI_MAX_REFERENCE_COUNT) {
|
|
|
ACPI_WARNING((AE_INFO,
|
|
|
- "Large Reference Count (0x%X) in object %p",
|
|
|
- count, object));
|
|
|
+ "Large Reference Count (0x%X) in object %p, Type=0x%.2X",
|
|
|
+ new_count, object, object->common.type));
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -702,7 +717,6 @@ void acpi_ut_remove_reference(union acpi_operand_object *object)
|
|
|
/*
|
|
|
* Allow a NULL pointer to be passed in, just ignore it. This saves
|
|
|
* each caller from having to check. Also, ignore NS nodes.
|
|
|
- *
|
|
|
*/
|
|
|
if (!object ||
|
|
|
(ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED)) {
|