Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/acpica/exmutex.c need to be fixed.

0001 
0002 /******************************************************************************
0003  *
0004  * Module Name: exmutex - ASL Mutex Acquire/Release functions
0005  *
0006  *****************************************************************************/
0007 
0008 /******************************************************************************
0009  *
0010  * 1. Copyright Notice
0011  *
0012  * Some or all of this work - Copyright (c) 1999 - 2009, Intel Corp.
0013  * All rights reserved.
0014  *
0015  * 2. License
0016  *
0017  * 2.1. This is your license from Intel Corp. under its intellectual property
0018  * rights.  You may have additional license terms from the party that provided
0019  * you this software, covering your right to use that party's intellectual
0020  * property rights.
0021  *
0022  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
0023  * copy of the source code appearing in this file ("Covered Code") an
0024  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
0025  * base code distributed originally by Intel ("Original Intel Code") to copy,
0026  * make derivatives, distribute, use and display any portion of the Covered
0027  * Code in any form, with the right to sublicense such rights; and
0028  *
0029  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
0030  * license (with the right to sublicense), under only those claims of Intel
0031  * patents that are infringed by the Original Intel Code, to make, use, sell,
0032  * offer to sell, and import the Covered Code and derivative works thereof
0033  * solely to the minimum extent necessary to exercise the above copyright
0034  * license, and in no event shall the patent license extend to any additions
0035  * to or modifications of the Original Intel Code.  No other license or right
0036  * is granted directly or by implication, estoppel or otherwise;
0037  *
0038  * The above copyright and patent license is granted only if the following
0039  * conditions are met:
0040  *
0041  * 3. Conditions
0042  *
0043  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
0044  * Redistribution of source code of any substantial portion of the Covered
0045  * Code or modification with rights to further distribute source must include
0046  * the above Copyright Notice, the above License, this list of Conditions,
0047  * and the following Disclaimer and Export Compliance provision.  In addition,
0048  * Licensee must cause all Covered Code to which Licensee contributes to
0049  * contain a file documenting the changes Licensee made to create that Covered
0050  * Code and the date of any change.  Licensee must include in that file the
0051  * documentation of any changes made by any predecessor Licensee.  Licensee
0052  * must include a prominent statement that the modification is derived,
0053  * directly or indirectly, from Original Intel Code.
0054  *
0055  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
0056  * Redistribution of source code of any substantial portion of the Covered
0057  * Code or modification without rights to further distribute source must
0058  * include the following Disclaimer and Export Compliance provision in the
0059  * documentation and/or other materials provided with distribution.  In
0060  * addition, Licensee may not authorize further sublicense of source of any
0061  * portion of the Covered Code, and must include terms to the effect that the
0062  * license from Licensee to its licensee is limited to the intellectual
0063  * property embodied in the software Licensee provides to its licensee, and
0064  * not to intellectual property embodied in modifications its licensee may
0065  * make.
0066  *
0067  * 3.3. Redistribution of Executable. Redistribution in executable form of any
0068  * substantial portion of the Covered Code or modification must reproduce the
0069  * above Copyright Notice, and the following Disclaimer and Export Compliance
0070  * provision in the documentation and/or other materials provided with the
0071  * distribution.
0072  *
0073  * 3.4. Intel retains all right, title, and interest in and to the Original
0074  * Intel Code.
0075  *
0076  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
0077  * Intel shall be used in advertising or otherwise to promote the sale, use or
0078  * other dealings in products derived from or relating to the Covered Code
0079  * without prior written authorization from Intel.
0080  *
0081  * 4. Disclaimer and Export Compliance
0082  *
0083  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
0084  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
0085  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
0086  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
0087  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
0088  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
0089  * PARTICULAR PURPOSE.
0090  *
0091  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
0092  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
0093  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
0094  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
0095  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
0096  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
0097  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
0098  * LIMITED REMEDY.
0099  *
0100  * 4.3. Licensee shall not export, either directly or indirectly, any of this
0101  * software or system incorporating such software without first obtaining any
0102  * required license or other approval from the U. S. Department of Commerce or
0103  * any other agency or department of the United States Government.  In the
0104  * event Licensee exports any such software from the United States or
0105  * re-exports any such software from a foreign destination, Licensee shall
0106  * ensure that the distribution and export/re-export of the software is in
0107  * compliance with all laws, regulations, orders, or other restrictions of the
0108  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
0109  * any of its subsidiaries will export/re-export any technical data, process,
0110  * software, or service, directly or indirectly, to any country for which the
0111  * United States government or any agency thereof requires an export license,
0112  * other governmental approval, or letter of assurance, without first obtaining
0113  * such license, approval or letter.
0114  *
0115  *****************************************************************************/
0116 
0117 #define __EXMUTEX_C__
0118 
0119 #include "acpi.h"
0120 #include "accommon.h"
0121 #include "acinterp.h"
0122 #include "acevents.h"
0123 
0124 #define _COMPONENT          ACPI_EXECUTER
0125         ACPI_MODULE_NAME    ("exmutex")
0126 
0127 /* Local prototypes */
0128 
0129 static void
0130 AcpiExLinkMutex (
0131     ACPI_OPERAND_OBJECT     *ObjDesc,
0132     ACPI_THREAD_STATE       *Thread);
0133 
0134 
0135 /*******************************************************************************
0136  *
0137  * FUNCTION:    AcpiExUnlinkMutex
0138  *
0139  * PARAMETERS:  ObjDesc             - The mutex to be unlinked
0140  *
0141  * RETURN:      None
0142  *
0143  * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
0144  *
0145  ******************************************************************************/
0146 
0147 void
0148 AcpiExUnlinkMutex (
0149     ACPI_OPERAND_OBJECT     *ObjDesc)
0150 {
0151     ACPI_THREAD_STATE       *Thread = ObjDesc->Mutex.OwnerThread;
0152 
0153 
0154     if (!Thread)
0155     {
0156         return;
0157     }
0158 
0159     /* Doubly linked list */
0160 
0161     if (ObjDesc->Mutex.Next)
0162     {
0163         (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev;
0164     }
0165 
0166     if (ObjDesc->Mutex.Prev)
0167     {
0168         (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next;
0169 
0170         /*
0171          * Migrate the previous sync level associated with this mutex to the
0172          * previous mutex on the list so that it may be preserved. This handles
0173          * the case where several mutexes have been acquired at the same level,
0174          * but are not released in opposite order.
0175          */
0176         (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel =
0177             ObjDesc->Mutex.OriginalSyncLevel;
0178     }
0179     else
0180     {
0181         Thread->AcquiredMutexList = ObjDesc->Mutex.Next;
0182     }
0183 }
0184 
0185 
0186 /*******************************************************************************
0187  *
0188  * FUNCTION:    AcpiExLinkMutex
0189  *
0190  * PARAMETERS:  ObjDesc         - The mutex to be linked
0191  *              Thread          - Current executing thread object
0192  *
0193  * RETURN:      None
0194  *
0195  * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
0196  *
0197  ******************************************************************************/
0198 
0199 static void
0200 AcpiExLinkMutex (
0201     ACPI_OPERAND_OBJECT     *ObjDesc,
0202     ACPI_THREAD_STATE       *Thread)
0203 {
0204     ACPI_OPERAND_OBJECT     *ListHead;
0205 
0206 
0207     ListHead = Thread->AcquiredMutexList;
0208 
0209     /* This object will be the first object in the list */
0210 
0211     ObjDesc->Mutex.Prev = NULL;
0212     ObjDesc->Mutex.Next = ListHead;
0213 
0214     /* Update old first object to point back to this object */
0215 
0216     if (ListHead)
0217     {
0218         ListHead->Mutex.Prev = ObjDesc;
0219     }
0220 
0221     /* Update list head */
0222 
0223     Thread->AcquiredMutexList = ObjDesc;
0224 }
0225 
0226 
0227 /*******************************************************************************
0228  *
0229  * FUNCTION:    AcpiExAcquireMutexObject
0230  *
0231  * PARAMETERS:  TimeDesc            - Timeout in milliseconds
0232  *              ObjDesc             - Mutex object
0233  *              Thread              - Current thread state
0234  *
0235  * RETURN:      Status
0236  *
0237  * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
0238  *              path that supports multiple acquires by the same thread.
0239  *
0240  * MUTEX:       Interpreter must be locked
0241  *
0242  * NOTE: This interface is called from three places:
0243  * 1) From AcpiExAcquireMutex, via an AML Acquire() operator
0244  * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the
0245  *    global lock
0246  * 3) From the external interface, AcpiAcquireGlobalLock
0247  *
0248  ******************************************************************************/
0249 
0250 ACPI_STATUS
0251 AcpiExAcquireMutexObject (
0252     UINT16                  Timeout,
0253     ACPI_OPERAND_OBJECT     *ObjDesc,
0254     ACPI_THREAD_ID          ThreadId)
0255 {
0256     ACPI_STATUS             Status;
0257 
0258 
0259     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc);
0260 
0261 
0262     if (!ObjDesc)
0263     {
0264         return_ACPI_STATUS (AE_BAD_PARAMETER);
0265     }
0266 
0267     /* Support for multiple acquires by the owning thread */
0268 
0269     if (ObjDesc->Mutex.ThreadId == ThreadId)
0270     {
0271         /*
0272          * The mutex is already owned by this thread, just increment the
0273          * acquisition depth
0274          */
0275         ObjDesc->Mutex.AcquisitionDepth++;
0276         return_ACPI_STATUS (AE_OK);
0277     }
0278 
0279     /* Acquire the mutex, wait if necessary. Special case for Global Lock */
0280 
0281     if (ObjDesc == AcpiGbl_GlobalLockMutex)
0282     {
0283         Status = AcpiEvAcquireGlobalLock (Timeout);
0284     }
0285     else
0286     {
0287         Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex,
0288                     Timeout);
0289     }
0290 
0291     if (ACPI_FAILURE (Status))
0292     {
0293         /* Includes failure from a timeout on TimeDesc */
0294 
0295         return_ACPI_STATUS (Status);
0296     }
0297 
0298     /* Acquired the mutex: update mutex object */
0299 
0300     ObjDesc->Mutex.ThreadId = ThreadId;
0301     ObjDesc->Mutex.AcquisitionDepth = 1;
0302     ObjDesc->Mutex.OriginalSyncLevel = 0;
0303     ObjDesc->Mutex.OwnerThread = NULL;      /* Used only for AML Acquire() */
0304 
0305     return_ACPI_STATUS (AE_OK);
0306 }
0307 
0308 
0309 /*******************************************************************************
0310  *
0311  * FUNCTION:    AcpiExAcquireMutex
0312  *
0313  * PARAMETERS:  TimeDesc            - Timeout integer
0314  *              ObjDesc             - Mutex object
0315  *              WalkState           - Current method execution state
0316  *
0317  * RETURN:      Status
0318  *
0319  * DESCRIPTION: Acquire an AML mutex
0320  *
0321  ******************************************************************************/
0322 
0323 ACPI_STATUS
0324 AcpiExAcquireMutex (
0325     ACPI_OPERAND_OBJECT     *TimeDesc,
0326     ACPI_OPERAND_OBJECT     *ObjDesc,
0327     ACPI_WALK_STATE         *WalkState)
0328 {
0329     ACPI_STATUS             Status;
0330 
0331 
0332     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);
0333 
0334 
0335     if (!ObjDesc)
0336     {
0337         return_ACPI_STATUS (AE_BAD_PARAMETER);
0338     }
0339 
0340     /* Must have a valid thread ID */
0341 
0342     if (!WalkState->Thread)
0343     {
0344         ACPI_ERROR ((AE_INFO, "Cannot acquire Mutex [%4.4s], null thread info",
0345             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
0346         return_ACPI_STATUS (AE_AML_INTERNAL);
0347     }
0348 
0349     /*
0350      * Current sync level must be less than or equal to the sync level of the
0351      * mutex. This mechanism provides some deadlock prevention
0352      */
0353     if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)
0354     {
0355         ACPI_ERROR ((AE_INFO,
0356             "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%d)",
0357             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
0358             WalkState->Thread->CurrentSyncLevel));
0359         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
0360     }
0361 
0362     Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value,
0363                 ObjDesc, WalkState->Thread->ThreadId);
0364     if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1)
0365     {
0366         /* Save Thread object, original/current sync levels */
0367 
0368         ObjDesc->Mutex.OwnerThread = WalkState->Thread;
0369         ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel;
0370         WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel;
0371 
0372         /* Link the mutex to the current thread for force-unlock at method exit */
0373 
0374         AcpiExLinkMutex (ObjDesc, WalkState->Thread);
0375     }
0376 
0377     return_ACPI_STATUS (Status);
0378 }
0379 
0380 
0381 /*******************************************************************************
0382  *
0383  * FUNCTION:    AcpiExReleaseMutexObject
0384  *
0385  * PARAMETERS:  ObjDesc             - The object descriptor for this op
0386  *
0387  * RETURN:      Status
0388  *
0389  * DESCRIPTION: Release a previously acquired Mutex, low level interface.
0390  *              Provides a common path that supports multiple releases (after
0391  *              previous multiple acquires) by the same thread.
0392  *
0393  * MUTEX:       Interpreter must be locked
0394  *
0395  * NOTE: This interface is called from three places:
0396  * 1) From AcpiExReleaseMutex, via an AML Acquire() operator
0397  * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the
0398  *    global lock
0399  * 3) From the external interface, AcpiReleaseGlobalLock
0400  *
0401  ******************************************************************************/
0402 
0403 ACPI_STATUS
0404 AcpiExReleaseMutexObject (
0405     ACPI_OPERAND_OBJECT     *ObjDesc)
0406 {
0407     ACPI_STATUS             Status = AE_OK;
0408 
0409 
0410     ACPI_FUNCTION_TRACE (ExReleaseMutexObject);
0411 
0412 
0413     if (ObjDesc->Mutex.AcquisitionDepth == 0)
0414     {
0415         return (AE_NOT_ACQUIRED);
0416     }
0417 
0418     /* Match multiple Acquires with multiple Releases */
0419 
0420     ObjDesc->Mutex.AcquisitionDepth--;
0421     if (ObjDesc->Mutex.AcquisitionDepth != 0)
0422     {
0423         /* Just decrement the depth and return */
0424 
0425         return_ACPI_STATUS (AE_OK);
0426     }
0427 
0428     if (ObjDesc->Mutex.OwnerThread)
0429     {
0430         /* Unlink the mutex from the owner's list */
0431 
0432         AcpiExUnlinkMutex (ObjDesc);
0433         ObjDesc->Mutex.OwnerThread = NULL;
0434     }
0435 
0436     /* Release the mutex, special case for Global Lock */
0437 
0438     if (ObjDesc == AcpiGbl_GlobalLockMutex)
0439     {
0440         Status = AcpiEvReleaseGlobalLock ();
0441     }
0442     else
0443     {
0444         AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
0445     }
0446 
0447     /* Clear mutex info */
0448 
0449     ObjDesc->Mutex.ThreadId = 0;
0450     return_ACPI_STATUS (Status);
0451 }
0452 
0453 
0454 /*******************************************************************************
0455  *
0456  * FUNCTION:    AcpiExReleaseMutex
0457  *
0458  * PARAMETERS:  ObjDesc             - The object descriptor for this op
0459  *              WalkState           - Current method execution state
0460  *
0461  * RETURN:      Status
0462  *
0463  * DESCRIPTION: Release a previously acquired Mutex.
0464  *
0465  ******************************************************************************/
0466 
0467 ACPI_STATUS
0468 AcpiExReleaseMutex (
0469     ACPI_OPERAND_OBJECT     *ObjDesc,
0470     ACPI_WALK_STATE         *WalkState)
0471 {
0472     ACPI_STATUS             Status = AE_OK;
0473     UINT8                   PreviousSyncLevel;
0474 
0475 
0476     ACPI_FUNCTION_TRACE (ExReleaseMutex);
0477 
0478 
0479     if (!ObjDesc)
0480     {
0481         return_ACPI_STATUS (AE_BAD_PARAMETER);
0482     }
0483 
0484     /* The mutex must have been previously acquired in order to release it */
0485 
0486     if (!ObjDesc->Mutex.OwnerThread)
0487     {
0488         ACPI_ERROR ((AE_INFO, "Cannot release Mutex [%4.4s], not acquired",
0489             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
0490         return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
0491     }
0492 
0493     /*
0494      * The Mutex is owned, but this thread must be the owner.
0495      * Special case for Global Lock, any thread can release
0496      */
0497     if ((ObjDesc->Mutex.OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&
0498         (ObjDesc != AcpiGbl_GlobalLockMutex))
0499     {
0500         ACPI_ERROR ((AE_INFO,
0501             "Thread %p cannot release Mutex [%4.4s] acquired by thread %p",
0502             ACPI_CAST_PTR (void, WalkState->Thread->ThreadId),
0503             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
0504             ACPI_CAST_PTR (void, ObjDesc->Mutex.OwnerThread->ThreadId)));
0505         return_ACPI_STATUS (AE_AML_NOT_OWNER);
0506     }
0507 
0508     /* Must have a valid thread ID */
0509 
0510     if (!WalkState->Thread)
0511     {
0512         ACPI_ERROR ((AE_INFO, "Cannot release Mutex [%4.4s], null thread info",
0513             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
0514         return_ACPI_STATUS (AE_AML_INTERNAL);
0515     }
0516 
0517     /*
0518      * The sync level of the mutex must be equal to the current sync level. In
0519      * other words, the current level means that at least one mutex at that
0520      * level is currently being held. Attempting to release a mutex of a
0521      * different level can only mean that the mutex ordering rule is being
0522      * violated. This behavior is clarified in ACPI 4.0 specification.
0523      */
0524     if (ObjDesc->Mutex.SyncLevel != WalkState->Thread->CurrentSyncLevel)
0525     {
0526         ACPI_ERROR ((AE_INFO,
0527             "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d",
0528             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
0529             ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel));
0530         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
0531     }
0532 
0533     /*
0534      * Get the previous SyncLevel from the head of the acquired mutex list.
0535      * This handles the case where several mutexes at the same level have been
0536      * acquired, but are not released in reverse order.
0537      */
0538     PreviousSyncLevel =
0539         WalkState->Thread->AcquiredMutexList->Mutex.OriginalSyncLevel;
0540 
0541     Status = AcpiExReleaseMutexObject (ObjDesc);
0542     if (ACPI_FAILURE (Status))
0543     {
0544         return_ACPI_STATUS (Status);
0545     }
0546 
0547     if (ObjDesc->Mutex.AcquisitionDepth == 0)
0548     {
0549         /* Restore the previous SyncLevel */
0550 
0551         WalkState->Thread->CurrentSyncLevel = PreviousSyncLevel;
0552     }
0553     return_ACPI_STATUS (Status);
0554 }
0555 
0556 
0557 /*******************************************************************************
0558  *
0559  * FUNCTION:    AcpiExReleaseAllMutexes
0560  *
0561  * PARAMETERS:  Thread          - Current executing thread object
0562  *
0563  * RETURN:      Status
0564  *
0565  * DESCRIPTION: Release all mutexes held by this thread
0566  *
0567  * NOTE: This function is called as the thread is exiting the interpreter.
0568  * Mutexes are not released when an individual control method is exited, but
0569  * only when the parent thread actually exits the interpreter. This allows one
0570  * method to acquire a mutex, and a different method to release it, as long as
0571  * this is performed underneath a single parent control method.
0572  *
0573  ******************************************************************************/
0574 
0575 void
0576 AcpiExReleaseAllMutexes (
0577     ACPI_THREAD_STATE       *Thread)
0578 {
0579     ACPI_OPERAND_OBJECT     *Next = Thread->AcquiredMutexList;
0580     ACPI_OPERAND_OBJECT     *ObjDesc;
0581 
0582 
0583     ACPI_FUNCTION_ENTRY ();
0584 
0585 
0586     /* Traverse the list of owned mutexes, releasing each one */
0587 
0588     while (Next)
0589     {
0590         ObjDesc = Next;
0591         Next = ObjDesc->Mutex.Next;
0592 
0593         ObjDesc->Mutex.Prev = NULL;
0594         ObjDesc->Mutex.Next = NULL;
0595         ObjDesc->Mutex.AcquisitionDepth = 0;
0596 
0597         /* Release the mutex, special case for Global Lock */
0598 
0599         if (ObjDesc == AcpiGbl_GlobalLockMutex)
0600         {
0601             /* Ignore errors */
0602 
0603             (void) AcpiEvReleaseGlobalLock ();
0604         }
0605         else
0606         {
0607             AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
0608         }
0609 
0610         /* Mark mutex unowned */
0611 
0612         ObjDesc->Mutex.OwnerThread = NULL;
0613         ObjDesc->Mutex.ThreadId = 0;
0614 
0615         /* Update Thread SyncLevel (Last mutex is the important one) */
0616 
0617         Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
0618     }
0619 }
0620 
0621