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