Home | History | Annotate | Line # | Download | only in executer
exmutex.c revision 1.1.1.2.2.2
      1 
      2 /******************************************************************************
      3  *
      4  * Module Name: exmutex - ASL Mutex Acquire/Release functions
      5  *
      6  *****************************************************************************/
      7 
      8 /*
      9  * Copyright (C) 2000 - 2011, Intel Corp.
     10  * All rights reserved.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions, and the following disclaimer,
     17  *    without modification.
     18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     19  *    substantially similar to the "NO WARRANTY" disclaimer below
     20  *    ("Disclaimer") and any redistribution must be conditioned upon
     21  *    including a substantially similar Disclaimer requirement for further
     22  *    binary redistribution.
     23  * 3. Neither the names of the above-listed copyright holders nor the names
     24  *    of any contributors may be used to endorse or promote products derived
     25  *    from this software without specific prior written permission.
     26  *
     27  * Alternatively, this software may be distributed under the terms of the
     28  * GNU General Public License ("GPL") version 2 as published by the Free
     29  * Software Foundation.
     30  *
     31  * NO WARRANTY
     32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     42  * POSSIBILITY OF SUCH DAMAGES.
     43  */
     44 
     45 #define __EXMUTEX_C__
     46 
     47 #include "acpi.h"
     48 #include "accommon.h"
     49 #include "acinterp.h"
     50 #include "acevents.h"
     51 
     52 #define _COMPONENT          ACPI_EXECUTER
     53         ACPI_MODULE_NAME    ("exmutex")
     54 
     55 /* Local prototypes */
     56 
     57 static void
     58 AcpiExLinkMutex (
     59     ACPI_OPERAND_OBJECT     *ObjDesc,
     60     ACPI_THREAD_STATE       *Thread);
     61 
     62 
     63 /*******************************************************************************
     64  *
     65  * FUNCTION:    AcpiExUnlinkMutex
     66  *
     67  * PARAMETERS:  ObjDesc             - The mutex to be unlinked
     68  *
     69  * RETURN:      None
     70  *
     71  * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
     72  *
     73  ******************************************************************************/
     74 
     75 void
     76 AcpiExUnlinkMutex (
     77     ACPI_OPERAND_OBJECT     *ObjDesc)
     78 {
     79     ACPI_THREAD_STATE       *Thread = ObjDesc->Mutex.OwnerThread;
     80 
     81 
     82     if (!Thread)
     83     {
     84         return;
     85     }
     86 
     87     /* Doubly linked list */
     88 
     89     if (ObjDesc->Mutex.Next)
     90     {
     91         (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev;
     92     }
     93 
     94     if (ObjDesc->Mutex.Prev)
     95     {
     96         (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next;
     97 
     98         /*
     99          * Migrate the previous sync level associated with this mutex to
    100          * the previous mutex on the list so that it may be preserved.
    101          * This handles the case where several mutexes have been acquired
    102          * at the same level, but are not released in opposite order.
    103          */
    104         (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel =
    105             ObjDesc->Mutex.OriginalSyncLevel;
    106     }
    107     else
    108     {
    109         Thread->AcquiredMutexList = ObjDesc->Mutex.Next;
    110     }
    111 }
    112 
    113 
    114 /*******************************************************************************
    115  *
    116  * FUNCTION:    AcpiExLinkMutex
    117  *
    118  * PARAMETERS:  ObjDesc             - The mutex to be linked
    119  *              Thread              - Current executing thread object
    120  *
    121  * RETURN:      None
    122  *
    123  * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
    124  *
    125  ******************************************************************************/
    126 
    127 static void
    128 AcpiExLinkMutex (
    129     ACPI_OPERAND_OBJECT     *ObjDesc,
    130     ACPI_THREAD_STATE       *Thread)
    131 {
    132     ACPI_OPERAND_OBJECT     *ListHead;
    133 
    134 
    135     ListHead = Thread->AcquiredMutexList;
    136 
    137     /* This object will be the first object in the list */
    138 
    139     ObjDesc->Mutex.Prev = NULL;
    140     ObjDesc->Mutex.Next = ListHead;
    141 
    142     /* Update old first object to point back to this object */
    143 
    144     if (ListHead)
    145     {
    146         ListHead->Mutex.Prev = ObjDesc;
    147     }
    148 
    149     /* Update list head */
    150 
    151     Thread->AcquiredMutexList = ObjDesc;
    152 }
    153 
    154 
    155 /*******************************************************************************
    156  *
    157  * FUNCTION:    AcpiExAcquireMutexObject
    158  *
    159  * PARAMETERS:  Timeout             - Timeout in milliseconds
    160  *              ObjDesc             - Mutex object
    161  *              ThreadId            - Current thread state
    162  *
    163  * RETURN:      Status
    164  *
    165  * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
    166  *              path that supports multiple acquires by the same thread.
    167  *
    168  * MUTEX:       Interpreter must be locked
    169  *
    170  * NOTE: This interface is called from three places:
    171  * 1) From AcpiExAcquireMutex, via an AML Acquire() operator
    172  * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the
    173  *    global lock
    174  * 3) From the external interface, AcpiAcquireGlobalLock
    175  *
    176  ******************************************************************************/
    177 
    178 ACPI_STATUS
    179 AcpiExAcquireMutexObject (
    180     UINT16                  Timeout,
    181     ACPI_OPERAND_OBJECT     *ObjDesc,
    182     ACPI_THREAD_ID          ThreadId)
    183 {
    184     ACPI_STATUS             Status;
    185 
    186 
    187     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc);
    188 
    189 
    190     if (!ObjDesc)
    191     {
    192         return_ACPI_STATUS (AE_BAD_PARAMETER);
    193     }
    194 
    195     /* Support for multiple acquires by the owning thread */
    196 
    197     if (ObjDesc->Mutex.ThreadId == ThreadId)
    198     {
    199         /*
    200          * The mutex is already owned by this thread, just increment the
    201          * acquisition depth
    202          */
    203         ObjDesc->Mutex.AcquisitionDepth++;
    204         return_ACPI_STATUS (AE_OK);
    205     }
    206 
    207     /* Acquire the mutex, wait if necessary. Special case for Global Lock */
    208 
    209     if (ObjDesc == AcpiGbl_GlobalLockMutex)
    210     {
    211         Status = AcpiEvAcquireGlobalLock (Timeout);
    212     }
    213     else
    214     {
    215         Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex,
    216                     Timeout);
    217     }
    218 
    219     if (ACPI_FAILURE (Status))
    220     {
    221         /* Includes failure from a timeout on TimeDesc */
    222 
    223         return_ACPI_STATUS (Status);
    224     }
    225 
    226     /* Acquired the mutex: update mutex object */
    227 
    228     ObjDesc->Mutex.ThreadId = ThreadId;
    229     ObjDesc->Mutex.AcquisitionDepth = 1;
    230     ObjDesc->Mutex.OriginalSyncLevel = 0;
    231     ObjDesc->Mutex.OwnerThread = NULL;      /* Used only for AML Acquire() */
    232 
    233     return_ACPI_STATUS (AE_OK);
    234 }
    235 
    236 
    237 /*******************************************************************************
    238  *
    239  * FUNCTION:    AcpiExAcquireMutex
    240  *
    241  * PARAMETERS:  TimeDesc            - Timeout integer
    242  *              ObjDesc             - Mutex object
    243  *              WalkState           - Current method execution state
    244  *
    245  * RETURN:      Status
    246  *
    247  * DESCRIPTION: Acquire an AML mutex
    248  *
    249  ******************************************************************************/
    250 
    251 ACPI_STATUS
    252 AcpiExAcquireMutex (
    253     ACPI_OPERAND_OBJECT     *TimeDesc,
    254     ACPI_OPERAND_OBJECT     *ObjDesc,
    255     ACPI_WALK_STATE         *WalkState)
    256 {
    257     ACPI_STATUS             Status;
    258 
    259 
    260     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);
    261 
    262 
    263     if (!ObjDesc)
    264     {
    265         return_ACPI_STATUS (AE_BAD_PARAMETER);
    266     }
    267 
    268     /* Must have a valid thread state struct */
    269 
    270     if (!WalkState->Thread)
    271     {
    272         ACPI_ERROR ((AE_INFO,
    273             "Cannot acquire Mutex [%4.4s], null thread info",
    274             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
    275         return_ACPI_STATUS (AE_AML_INTERNAL);
    276     }
    277 
    278     /*
    279      * Current sync level must be less than or equal to the sync level of the
    280      * mutex. This mechanism provides some deadlock prevention
    281      */
    282     if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)
    283     {
    284         ACPI_ERROR ((AE_INFO,
    285             "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%u)",
    286             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
    287             WalkState->Thread->CurrentSyncLevel));
    288         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
    289     }
    290 
    291     Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value,
    292                 ObjDesc, WalkState->Thread->ThreadId);
    293     if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1)
    294     {
    295         /* Save Thread object, original/current sync levels */
    296 
    297         ObjDesc->Mutex.OwnerThread = WalkState->Thread;
    298         ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel;
    299         WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel;
    300 
    301         /* Link the mutex to the current thread for force-unlock at method exit */
    302 
    303         AcpiExLinkMutex (ObjDesc, WalkState->Thread);
    304     }
    305 
    306     return_ACPI_STATUS (Status);
    307 }
    308 
    309 
    310 /*******************************************************************************
    311  *
    312  * FUNCTION:    AcpiExReleaseMutexObject
    313  *
    314  * PARAMETERS:  ObjDesc             - The object descriptor for this op
    315  *
    316  * RETURN:      Status
    317  *
    318  * DESCRIPTION: Release a previously acquired Mutex, low level interface.
    319  *              Provides a common path that supports multiple releases (after
    320  *              previous multiple acquires) by the same thread.
    321  *
    322  * MUTEX:       Interpreter must be locked
    323  *
    324  * NOTE: This interface is called from three places:
    325  * 1) From AcpiExReleaseMutex, via an AML Acquire() operator
    326  * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the
    327  *    global lock
    328  * 3) From the external interface, AcpiReleaseGlobalLock
    329  *
    330  ******************************************************************************/
    331 
    332 ACPI_STATUS
    333 AcpiExReleaseMutexObject (
    334     ACPI_OPERAND_OBJECT     *ObjDesc)
    335 {
    336     ACPI_STATUS             Status = AE_OK;
    337 
    338 
    339     ACPI_FUNCTION_TRACE (ExReleaseMutexObject);
    340 
    341 
    342     if (ObjDesc->Mutex.AcquisitionDepth == 0)
    343     {
    344         return (AE_NOT_ACQUIRED);
    345     }
    346 
    347     /* Match multiple Acquires with multiple Releases */
    348 
    349     ObjDesc->Mutex.AcquisitionDepth--;
    350     if (ObjDesc->Mutex.AcquisitionDepth != 0)
    351     {
    352         /* Just decrement the depth and return */
    353 
    354         return_ACPI_STATUS (AE_OK);
    355     }
    356 
    357     if (ObjDesc->Mutex.OwnerThread)
    358     {
    359         /* Unlink the mutex from the owner's list */
    360 
    361         AcpiExUnlinkMutex (ObjDesc);
    362         ObjDesc->Mutex.OwnerThread = NULL;
    363     }
    364 
    365     /* Release the mutex, special case for Global Lock */
    366 
    367     if (ObjDesc == AcpiGbl_GlobalLockMutex)
    368     {
    369         Status = AcpiEvReleaseGlobalLock ();
    370     }
    371     else
    372     {
    373         AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
    374     }
    375 
    376     /* Clear mutex info */
    377 
    378     ObjDesc->Mutex.ThreadId = 0;
    379     return_ACPI_STATUS (Status);
    380 }
    381 
    382 
    383 /*******************************************************************************
    384  *
    385  * FUNCTION:    AcpiExReleaseMutex
    386  *
    387  * PARAMETERS:  ObjDesc             - The object descriptor for this op
    388  *              WalkState           - Current method execution state
    389  *
    390  * RETURN:      Status
    391  *
    392  * DESCRIPTION: Release a previously acquired Mutex.
    393  *
    394  ******************************************************************************/
    395 
    396 ACPI_STATUS
    397 AcpiExReleaseMutex (
    398     ACPI_OPERAND_OBJECT     *ObjDesc,
    399     ACPI_WALK_STATE         *WalkState)
    400 {
    401     ACPI_STATUS             Status = AE_OK;
    402     UINT8                   PreviousSyncLevel;
    403     ACPI_THREAD_STATE       *OwnerThread;
    404 
    405 
    406     ACPI_FUNCTION_TRACE (ExReleaseMutex);
    407 
    408 
    409     if (!ObjDesc)
    410     {
    411         return_ACPI_STATUS (AE_BAD_PARAMETER);
    412     }
    413 
    414     OwnerThread = ObjDesc->Mutex.OwnerThread;
    415 
    416     /* The mutex must have been previously acquired in order to release it */
    417 
    418     if (!OwnerThread)
    419     {
    420         ACPI_ERROR ((AE_INFO,
    421             "Cannot release Mutex [%4.4s], not acquired",
    422             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
    423         return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
    424     }
    425 
    426     /* Must have a valid thread ID */
    427 
    428     if (!WalkState->Thread)
    429     {
    430         ACPI_ERROR ((AE_INFO,
    431             "Cannot release Mutex [%4.4s], null thread info",
    432             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
    433         return_ACPI_STATUS (AE_AML_INTERNAL);
    434     }
    435 
    436     /*
    437      * The Mutex is owned, but this thread must be the owner.
    438      * Special case for Global Lock, any thread can release
    439      */
    440     if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&
    441         (ObjDesc != AcpiGbl_GlobalLockMutex))
    442     {
    443         ACPI_ERROR ((AE_INFO,
    444             "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
    445             (UINT32) WalkState->Thread->ThreadId,
    446             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
    447             (UINT32) OwnerThread->ThreadId));
    448         return_ACPI_STATUS (AE_AML_NOT_OWNER);
    449     }
    450 
    451     /*
    452      * The sync level of the mutex must be equal to the current sync level. In
    453      * other words, the current level means that at least one mutex at that
    454      * level is currently being held. Attempting to release a mutex of a
    455      * different level can only mean that the mutex ordering rule is being
    456      * violated. This behavior is clarified in ACPI 4.0 specification.
    457      */
    458     if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel)
    459     {
    460         ACPI_ERROR ((AE_INFO,
    461             "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %u current %u",
    462             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
    463             ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel));
    464         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
    465     }
    466 
    467     /*
    468      * Get the previous SyncLevel from the head of the acquired mutex list.
    469      * This handles the case where several mutexes at the same level have been
    470      * acquired, but are not released in reverse order.
    471      */
    472     PreviousSyncLevel =
    473         OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel;
    474 
    475     Status = AcpiExReleaseMutexObject (ObjDesc);
    476     if (ACPI_FAILURE (Status))
    477     {
    478         return_ACPI_STATUS (Status);
    479     }
    480 
    481     if (ObjDesc->Mutex.AcquisitionDepth == 0)
    482     {
    483         /* Restore the previous SyncLevel */
    484 
    485         OwnerThread->CurrentSyncLevel = PreviousSyncLevel;
    486     }
    487 
    488     return_ACPI_STATUS (Status);
    489 }
    490 
    491 
    492 /*******************************************************************************
    493  *
    494  * FUNCTION:    AcpiExReleaseAllMutexes
    495  *
    496  * PARAMETERS:  Thread              - Current executing thread object
    497  *
    498  * RETURN:      Status
    499  *
    500  * DESCRIPTION: Release all mutexes held by this thread
    501  *
    502  * NOTE: This function is called as the thread is exiting the interpreter.
    503  * Mutexes are not released when an individual control method is exited, but
    504  * only when the parent thread actually exits the interpreter. This allows one
    505  * method to acquire a mutex, and a different method to release it, as long as
    506  * this is performed underneath a single parent control method.
    507  *
    508  ******************************************************************************/
    509 
    510 void
    511 AcpiExReleaseAllMutexes (
    512     ACPI_THREAD_STATE       *Thread)
    513 {
    514     ACPI_OPERAND_OBJECT     *Next = Thread->AcquiredMutexList;
    515     ACPI_OPERAND_OBJECT     *ObjDesc;
    516 
    517 
    518     ACPI_FUNCTION_ENTRY ();
    519 
    520 
    521     /* Traverse the list of owned mutexes, releasing each one */
    522 
    523     while (Next)
    524     {
    525         ObjDesc = Next;
    526         Next = ObjDesc->Mutex.Next;
    527 
    528         ObjDesc->Mutex.Prev = NULL;
    529         ObjDesc->Mutex.Next = NULL;
    530         ObjDesc->Mutex.AcquisitionDepth = 0;
    531 
    532         /* Release the mutex, special case for Global Lock */
    533 
    534         if (ObjDesc == AcpiGbl_GlobalLockMutex)
    535         {
    536             /* Ignore errors */
    537 
    538             (void) AcpiEvReleaseGlobalLock ();
    539         }
    540         else
    541         {
    542             AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
    543         }
    544 
    545         /* Mark mutex unowned */
    546 
    547         ObjDesc->Mutex.OwnerThread = NULL;
    548         ObjDesc->Mutex.ThreadId = 0;
    549 
    550         /* Update Thread SyncLevel (Last mutex is the important one) */
    551 
    552         Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
    553     }
    554 }
    555