Home | History | Annotate | Line # | Download | only in executer
exmutex.c revision 1.1
      1 
      2 /******************************************************************************
      3  *
      4  * Module Name: exmutex - ASL Mutex Acquire/Release functions
      5  *
      6  *****************************************************************************/
      7 
      8 /******************************************************************************
      9  *
     10  * 1. Copyright Notice
     11  *
     12  * Some or all of this work - Copyright (c) 1999 - 2010, Intel Corp.
     13  * All rights reserved.
     14  *
     15  * 2. License
     16  *
     17  * 2.1. This is your license from Intel Corp. under its intellectual property
     18  * rights.  You may have additional license terms from the party that provided
     19  * you this software, covering your right to use that party's intellectual
     20  * property rights.
     21  *
     22  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
     23  * copy of the source code appearing in this file ("Covered Code") an
     24  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
     25  * base code distributed originally by Intel ("Original Intel Code") to copy,
     26  * make derivatives, distribute, use and display any portion of the Covered
     27  * Code in any form, with the right to sublicense such rights; and
     28  *
     29  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
     30  * license (with the right to sublicense), under only those claims of Intel
     31  * patents that are infringed by the Original Intel Code, to make, use, sell,
     32  * offer to sell, and import the Covered Code and derivative works thereof
     33  * solely to the minimum extent necessary to exercise the above copyright
     34  * license, and in no event shall the patent license extend to any additions
     35  * to or modifications of the Original Intel Code.  No other license or right
     36  * is granted directly or by implication, estoppel or otherwise;
     37  *
     38  * The above copyright and patent license is granted only if the following
     39  * conditions are met:
     40  *
     41  * 3. Conditions
     42  *
     43  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
     44  * Redistribution of source code of any substantial portion of the Covered
     45  * Code or modification with rights to further distribute source must include
     46  * the above Copyright Notice, the above License, this list of Conditions,
     47  * and the following Disclaimer and Export Compliance provision.  In addition,
     48  * Licensee must cause all Covered Code to which Licensee contributes to
     49  * contain a file documenting the changes Licensee made to create that Covered
     50  * Code and the date of any change.  Licensee must include in that file the
     51  * documentation of any changes made by any predecessor Licensee.  Licensee
     52  * must include a prominent statement that the modification is derived,
     53  * directly or indirectly, from Original Intel Code.
     54  *
     55  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
     56  * Redistribution of source code of any substantial portion of the Covered
     57  * Code or modification without rights to further distribute source must
     58  * include the following Disclaimer and Export Compliance provision in the
     59  * documentation and/or other materials provided with distribution.  In
     60  * addition, Licensee may not authorize further sublicense of source of any
     61  * portion of the Covered Code, and must include terms to the effect that the
     62  * license from Licensee to its licensee is limited to the intellectual
     63  * property embodied in the software Licensee provides to its licensee, and
     64  * not to intellectual property embodied in modifications its licensee may
     65  * make.
     66  *
     67  * 3.3. Redistribution of Executable. Redistribution in executable form of any
     68  * substantial portion of the Covered Code or modification must reproduce the
     69  * above Copyright Notice, and the following Disclaimer and Export Compliance
     70  * provision in the documentation and/or other materials provided with the
     71  * distribution.
     72  *
     73  * 3.4. Intel retains all right, title, and interest in and to the Original
     74  * Intel Code.
     75  *
     76  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
     77  * Intel shall be used in advertising or otherwise to promote the sale, use or
     78  * other dealings in products derived from or relating to the Covered Code
     79  * without prior written authorization from Intel.
     80  *
     81  * 4. Disclaimer and Export Compliance
     82  *
     83  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
     84  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
     85  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
     86  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
     87  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
     88  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
     89  * PARTICULAR PURPOSE.
     90  *
     91  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
     92  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
     93  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
     94  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
     95  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
     96  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
     97  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
     98  * LIMITED REMEDY.
     99  *
    100  * 4.3. Licensee shall not export, either directly or indirectly, any of this
    101  * software or system incorporating such software without first obtaining any
    102  * required license or other approval from the U. S. Department of Commerce or
    103  * any other agency or department of the United States Government.  In the
    104  * event Licensee exports any such software from the United States or
    105  * re-exports any such software from a foreign destination, Licensee shall
    106  * ensure that the distribution and export/re-export of the software is in
    107  * compliance with all laws, regulations, orders, or other restrictions of the
    108  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
    109  * any of its subsidiaries will export/re-export any technical data, process,
    110  * software, or service, directly or indirectly, to any country for which the
    111  * United States government or any agency thereof requires an export license,
    112  * other governmental approval, or letter of assurance, without first obtaining
    113  * such license, approval or letter.
    114  *
    115  *****************************************************************************/
    116 
    117 #define __EXMUTEX_C__
    118 
    119 #include "acpi.h"
    120 #include "accommon.h"
    121 #include "acinterp.h"
    122 #include "acevents.h"
    123 
    124 #define _COMPONENT          ACPI_EXECUTER
    125         ACPI_MODULE_NAME    ("exmutex")
    126 
    127 /* Local prototypes */
    128 
    129 static void
    130 AcpiExLinkMutex (
    131     ACPI_OPERAND_OBJECT     *ObjDesc,
    132     ACPI_THREAD_STATE       *Thread);
    133 
    134 
    135 /*******************************************************************************
    136  *
    137  * FUNCTION:    AcpiExUnlinkMutex
    138  *
    139  * PARAMETERS:  ObjDesc             - The mutex to be unlinked
    140  *
    141  * RETURN:      None
    142  *
    143  * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
    144  *
    145  ******************************************************************************/
    146 
    147 void
    148 AcpiExUnlinkMutex (
    149     ACPI_OPERAND_OBJECT     *ObjDesc)
    150 {
    151     ACPI_THREAD_STATE       *Thread = ObjDesc->Mutex.OwnerThread;
    152 
    153 
    154     if (!Thread)
    155     {
    156         return;
    157     }
    158 
    159     /* Doubly linked list */
    160 
    161     if (ObjDesc->Mutex.Next)
    162     {
    163         (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev;
    164     }
    165 
    166     if (ObjDesc->Mutex.Prev)
    167     {
    168         (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next;
    169 
    170         /*
    171          * Migrate the previous sync level associated with this mutex to
    172          * the previous mutex on the list so that it may be preserved.
    173          * This handles the case where several mutexes have been acquired
    174          * at the same level, but are not released in opposite order.
    175          */
    176         (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel =
    177             ObjDesc->Mutex.OriginalSyncLevel;
    178     }
    179     else
    180     {
    181         Thread->AcquiredMutexList = ObjDesc->Mutex.Next;
    182     }
    183 }
    184 
    185 
    186 /*******************************************************************************
    187  *
    188  * FUNCTION:    AcpiExLinkMutex
    189  *
    190  * PARAMETERS:  ObjDesc             - The mutex to be linked
    191  *              Thread              - Current executing thread object
    192  *
    193  * RETURN:      None
    194  *
    195  * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
    196  *
    197  ******************************************************************************/
    198 
    199 static void
    200 AcpiExLinkMutex (
    201     ACPI_OPERAND_OBJECT     *ObjDesc,
    202     ACPI_THREAD_STATE       *Thread)
    203 {
    204     ACPI_OPERAND_OBJECT     *ListHead;
    205 
    206 
    207     ListHead = Thread->AcquiredMutexList;
    208 
    209     /* This object will be the first object in the list */
    210 
    211     ObjDesc->Mutex.Prev = NULL;
    212     ObjDesc->Mutex.Next = ListHead;
    213 
    214     /* Update old first object to point back to this object */
    215 
    216     if (ListHead)
    217     {
    218         ListHead->Mutex.Prev = ObjDesc;
    219     }
    220 
    221     /* Update list head */
    222 
    223     Thread->AcquiredMutexList = ObjDesc;
    224 }
    225 
    226 
    227 /*******************************************************************************
    228  *
    229  * FUNCTION:    AcpiExAcquireMutexObject
    230  *
    231  * PARAMETERS:  Timeout             - Timeout in milliseconds
    232  *              ObjDesc             - Mutex object
    233  *              ThreadId            - Current thread state
    234  *
    235  * RETURN:      Status
    236  *
    237  * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
    238  *              path that supports multiple acquires by the same thread.
    239  *
    240  * MUTEX:       Interpreter must be locked
    241  *
    242  * NOTE: This interface is called from three places:
    243  * 1) From AcpiExAcquireMutex, via an AML Acquire() operator
    244  * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the
    245  *    global lock
    246  * 3) From the external interface, AcpiAcquireGlobalLock
    247  *
    248  ******************************************************************************/
    249 
    250 ACPI_STATUS
    251 AcpiExAcquireMutexObject (
    252     UINT16                  Timeout,
    253     ACPI_OPERAND_OBJECT     *ObjDesc,
    254     ACPI_THREAD_ID          ThreadId)
    255 {
    256     ACPI_STATUS             Status;
    257 
    258 
    259     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc);
    260 
    261 
    262     if (!ObjDesc)
    263     {
    264         return_ACPI_STATUS (AE_BAD_PARAMETER);
    265     }
    266 
    267     /* Support for multiple acquires by the owning thread */
    268 
    269     if (ObjDesc->Mutex.ThreadId == ThreadId)
    270     {
    271         /*
    272          * The mutex is already owned by this thread, just increment the
    273          * acquisition depth
    274          */
    275         ObjDesc->Mutex.AcquisitionDepth++;
    276         return_ACPI_STATUS (AE_OK);
    277     }
    278 
    279     /* Acquire the mutex, wait if necessary. Special case for Global Lock */
    280 
    281     if (ObjDesc == AcpiGbl_GlobalLockMutex)
    282     {
    283         Status = AcpiEvAcquireGlobalLock (Timeout);
    284     }
    285     else
    286     {
    287         Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex,
    288                     Timeout);
    289     }
    290 
    291     if (ACPI_FAILURE (Status))
    292     {
    293         /* Includes failure from a timeout on TimeDesc */
    294 
    295         return_ACPI_STATUS (Status);
    296     }
    297 
    298     /* Acquired the mutex: update mutex object */
    299 
    300     ObjDesc->Mutex.ThreadId = ThreadId;
    301     ObjDesc->Mutex.AcquisitionDepth = 1;
    302     ObjDesc->Mutex.OriginalSyncLevel = 0;
    303     ObjDesc->Mutex.OwnerThread = NULL;      /* Used only for AML Acquire() */
    304 
    305     return_ACPI_STATUS (AE_OK);
    306 }
    307 
    308 
    309 /*******************************************************************************
    310  *
    311  * FUNCTION:    AcpiExAcquireMutex
    312  *
    313  * PARAMETERS:  TimeDesc            - Timeout integer
    314  *              ObjDesc             - Mutex object
    315  *              WalkState           - Current method execution state
    316  *
    317  * RETURN:      Status
    318  *
    319  * DESCRIPTION: Acquire an AML mutex
    320  *
    321  ******************************************************************************/
    322 
    323 ACPI_STATUS
    324 AcpiExAcquireMutex (
    325     ACPI_OPERAND_OBJECT     *TimeDesc,
    326     ACPI_OPERAND_OBJECT     *ObjDesc,
    327     ACPI_WALK_STATE         *WalkState)
    328 {
    329     ACPI_STATUS             Status;
    330 
    331 
    332     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);
    333 
    334 
    335     if (!ObjDesc)
    336     {
    337         return_ACPI_STATUS (AE_BAD_PARAMETER);
    338     }
    339 
    340     /* Must have a valid thread state struct */
    341 
    342     if (!WalkState->Thread)
    343     {
    344         ACPI_ERROR ((AE_INFO,
    345             "Cannot acquire Mutex [%4.4s], null thread info",
    346             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
    347         return_ACPI_STATUS (AE_AML_INTERNAL);
    348     }
    349 
    350     /*
    351      * Current sync level must be less than or equal to the sync level of the
    352      * mutex. This mechanism provides some deadlock prevention
    353      */
    354     if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)
    355     {
    356         ACPI_ERROR ((AE_INFO,
    357             "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%u)",
    358             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
    359             WalkState->Thread->CurrentSyncLevel));
    360         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
    361     }
    362 
    363     Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value,
    364                 ObjDesc, WalkState->Thread->ThreadId);
    365     if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1)
    366     {
    367         /* Save Thread object, original/current sync levels */
    368 
    369         ObjDesc->Mutex.OwnerThread = WalkState->Thread;
    370         ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel;
    371         WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel;
    372 
    373         /* Link the mutex to the current thread for force-unlock at method exit */
    374 
    375         AcpiExLinkMutex (ObjDesc, WalkState->Thread);
    376     }
    377 
    378     return_ACPI_STATUS (Status);
    379 }
    380 
    381 
    382 /*******************************************************************************
    383  *
    384  * FUNCTION:    AcpiExReleaseMutexObject
    385  *
    386  * PARAMETERS:  ObjDesc             - The object descriptor for this op
    387  *
    388  * RETURN:      Status
    389  *
    390  * DESCRIPTION: Release a previously acquired Mutex, low level interface.
    391  *              Provides a common path that supports multiple releases (after
    392  *              previous multiple acquires) by the same thread.
    393  *
    394  * MUTEX:       Interpreter must be locked
    395  *
    396  * NOTE: This interface is called from three places:
    397  * 1) From AcpiExReleaseMutex, via an AML Acquire() operator
    398  * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the
    399  *    global lock
    400  * 3) From the external interface, AcpiReleaseGlobalLock
    401  *
    402  ******************************************************************************/
    403 
    404 ACPI_STATUS
    405 AcpiExReleaseMutexObject (
    406     ACPI_OPERAND_OBJECT     *ObjDesc)
    407 {
    408     ACPI_STATUS             Status = AE_OK;
    409 
    410 
    411     ACPI_FUNCTION_TRACE (ExReleaseMutexObject);
    412 
    413 
    414     if (ObjDesc->Mutex.AcquisitionDepth == 0)
    415     {
    416         return (AE_NOT_ACQUIRED);
    417     }
    418 
    419     /* Match multiple Acquires with multiple Releases */
    420 
    421     ObjDesc->Mutex.AcquisitionDepth--;
    422     if (ObjDesc->Mutex.AcquisitionDepth != 0)
    423     {
    424         /* Just decrement the depth and return */
    425 
    426         return_ACPI_STATUS (AE_OK);
    427     }
    428 
    429     if (ObjDesc->Mutex.OwnerThread)
    430     {
    431         /* Unlink the mutex from the owner's list */
    432 
    433         AcpiExUnlinkMutex (ObjDesc);
    434         ObjDesc->Mutex.OwnerThread = NULL;
    435     }
    436 
    437     /* Release the mutex, special case for Global Lock */
    438 
    439     if (ObjDesc == AcpiGbl_GlobalLockMutex)
    440     {
    441         Status = AcpiEvReleaseGlobalLock ();
    442     }
    443     else
    444     {
    445         AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
    446     }
    447 
    448     /* Clear mutex info */
    449 
    450     ObjDesc->Mutex.ThreadId = 0;
    451     return_ACPI_STATUS (Status);
    452 }
    453 
    454 
    455 /*******************************************************************************
    456  *
    457  * FUNCTION:    AcpiExReleaseMutex
    458  *
    459  * PARAMETERS:  ObjDesc             - The object descriptor for this op
    460  *              WalkState           - Current method execution state
    461  *
    462  * RETURN:      Status
    463  *
    464  * DESCRIPTION: Release a previously acquired Mutex.
    465  *
    466  ******************************************************************************/
    467 
    468 ACPI_STATUS
    469 AcpiExReleaseMutex (
    470     ACPI_OPERAND_OBJECT     *ObjDesc,
    471     ACPI_WALK_STATE         *WalkState)
    472 {
    473     ACPI_STATUS             Status = AE_OK;
    474     UINT8                   PreviousSyncLevel;
    475     ACPI_THREAD_STATE       *OwnerThread;
    476 
    477 
    478     ACPI_FUNCTION_TRACE (ExReleaseMutex);
    479 
    480 
    481     if (!ObjDesc)
    482     {
    483         return_ACPI_STATUS (AE_BAD_PARAMETER);
    484     }
    485 
    486     OwnerThread = ObjDesc->Mutex.OwnerThread;
    487 
    488     /* The mutex must have been previously acquired in order to release it */
    489 
    490     if (!OwnerThread)
    491     {
    492         ACPI_ERROR ((AE_INFO,
    493             "Cannot release Mutex [%4.4s], not acquired",
    494             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
    495         return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
    496     }
    497 
    498     /* Must have a valid thread ID */
    499 
    500     if (!WalkState->Thread)
    501     {
    502         ACPI_ERROR ((AE_INFO,
    503             "Cannot release Mutex [%4.4s], null thread info",
    504             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
    505         return_ACPI_STATUS (AE_AML_INTERNAL);
    506     }
    507 
    508     /*
    509      * The Mutex is owned, but this thread must be the owner.
    510      * Special case for Global Lock, any thread can release
    511      */
    512     if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&
    513         (ObjDesc != AcpiGbl_GlobalLockMutex))
    514     {
    515         ACPI_ERROR ((AE_INFO,
    516             "Thread %p cannot release Mutex [%4.4s] acquired by thread %p",
    517             ACPI_CAST_PTR (void, WalkState->Thread->ThreadId),
    518             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
    519             ACPI_CAST_PTR (void, OwnerThread->ThreadId)));
    520         return_ACPI_STATUS (AE_AML_NOT_OWNER);
    521     }
    522 
    523     /*
    524      * The sync level of the mutex must be equal to the current sync level. In
    525      * other words, the current level means that at least one mutex at that
    526      * level is currently being held. Attempting to release a mutex of a
    527      * different level can only mean that the mutex ordering rule is being
    528      * violated. This behavior is clarified in ACPI 4.0 specification.
    529      */
    530     if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel)
    531     {
    532         ACPI_ERROR ((AE_INFO,
    533             "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %u current %u",
    534             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
    535             ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel));
    536         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
    537     }
    538 
    539     /*
    540      * Get the previous SyncLevel from the head of the acquired mutex list.
    541      * This handles the case where several mutexes at the same level have been
    542      * acquired, but are not released in reverse order.
    543      */
    544     PreviousSyncLevel =
    545         OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel;
    546 
    547     Status = AcpiExReleaseMutexObject (ObjDesc);
    548     if (ACPI_FAILURE (Status))
    549     {
    550         return_ACPI_STATUS (Status);
    551     }
    552 
    553     if (ObjDesc->Mutex.AcquisitionDepth == 0)
    554     {
    555         /* Restore the previous SyncLevel */
    556 
    557         OwnerThread->CurrentSyncLevel = PreviousSyncLevel;
    558     }
    559 
    560     return_ACPI_STATUS (Status);
    561 }
    562 
    563 
    564 /*******************************************************************************
    565  *
    566  * FUNCTION:    AcpiExReleaseAllMutexes
    567  *
    568  * PARAMETERS:  Thread              - Current executing thread object
    569  *
    570  * RETURN:      Status
    571  *
    572  * DESCRIPTION: Release all mutexes held by this thread
    573  *
    574  * NOTE: This function is called as the thread is exiting the interpreter.
    575  * Mutexes are not released when an individual control method is exited, but
    576  * only when the parent thread actually exits the interpreter. This allows one
    577  * method to acquire a mutex, and a different method to release it, as long as
    578  * this is performed underneath a single parent control method.
    579  *
    580  ******************************************************************************/
    581 
    582 void
    583 AcpiExReleaseAllMutexes (
    584     ACPI_THREAD_STATE       *Thread)
    585 {
    586     ACPI_OPERAND_OBJECT     *Next = Thread->AcquiredMutexList;
    587     ACPI_OPERAND_OBJECT     *ObjDesc;
    588 
    589 
    590     ACPI_FUNCTION_ENTRY ();
    591 
    592 
    593     /* Traverse the list of owned mutexes, releasing each one */
    594 
    595     while (Next)
    596     {
    597         ObjDesc = Next;
    598         Next = ObjDesc->Mutex.Next;
    599 
    600         ObjDesc->Mutex.Prev = NULL;
    601         ObjDesc->Mutex.Next = NULL;
    602         ObjDesc->Mutex.AcquisitionDepth = 0;
    603 
    604         /* Release the mutex, special case for Global Lock */
    605 
    606         if (ObjDesc == AcpiGbl_GlobalLockMutex)
    607         {
    608             /* Ignore errors */
    609 
    610             (void) AcpiEvReleaseGlobalLock ();
    611         }
    612         else
    613         {
    614             AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
    615         }
    616 
    617         /* Mark mutex unowned */
    618 
    619         ObjDesc->Mutex.OwnerThread = NULL;
    620         ObjDesc->Mutex.ThreadId = 0;
    621 
    622         /* Update Thread SyncLevel (Last mutex is the important one) */
    623 
    624         Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
    625     }
    626 }
    627