ReactOS  0.4.13-dev-257-gfabbd7c
mutex.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: ntoskrnl/ke/mutex.c
5  * PURPOSE: Implements the Mutant Dispatcher Object
6  * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* FUNCTIONS *****************************************************************/
16 
17 /*
18  * @implemented
19  */
20 VOID
21 NTAPI
24 {
25  PKTHREAD CurrentThread;
26  KIRQL OldIrql;
27 
28  /* Check if we have an initial owner */
29  if (InitialOwner)
30  {
31  /* We also need to associate a thread */
32  CurrentThread = KeGetCurrentThread();
33  Mutant->OwnerThread = CurrentThread;
34 
35  /* We're about to touch the Thread, so lock the Dispatcher */
37 
38  /* And insert it into its list */
39  InsertTailList(&CurrentThread->MutantListHead,
40  &Mutant->MutantListEntry);
41 
42  /* Release Dispatcher Lock */
44  }
45  else
46  {
47  /* In this case, we don't have an owner yet */
48  Mutant->OwnerThread = NULL;
49  }
50 
51  /* Now we set up the Dispatcher Header */
52  Mutant->Header.Type = MutantObject;
53  Mutant->Header.Size = sizeof(KMUTANT) / sizeof(ULONG);
54  Mutant->Header.SignalState = InitialOwner ? 0 : 1;
55  InitializeListHead(&(Mutant->Header.WaitListHead));
56 
57  /* Initialize the default data */
58  Mutant->Abandoned = FALSE;
59  Mutant->ApcDisable = 0;
60 }
61 
62 /*
63  * @implemented
64  */
65 VOID
66 NTAPI
68  IN ULONG Level)
69 {
70  /* Set up the Dispatcher Header */
71  Mutex->Header.Type = MutantObject;
72  Mutex->Header.Size = sizeof(KMUTEX) / sizeof(ULONG);
73  Mutex->Header.SignalState = 1;
74  InitializeListHead(&(Mutex->Header.WaitListHead));
75 
76  /* Initialize the default data */
77  Mutex->OwnerThread = NULL;
78  Mutex->Abandoned = FALSE;
79  Mutex->ApcDisable = 1;
80 }
81 
82 /*
83  * @implemented
84  */
85 LONG
86 NTAPI
88 {
89  /* Return the Signal State */
90  return Mutant->Header.SignalState;
91 }
92 
93 /*
94  * @implemented
95  */
96 LONG
97 NTAPI
100  IN BOOLEAN Abandon,
101  IN BOOLEAN Wait)
102 {
103  KIRQL OldIrql;
105  PKTHREAD CurrentThread = KeGetCurrentThread();
106  BOOLEAN EnableApc = FALSE;
107  ASSERT_MUTANT(Mutant);
109 
110  /* Lock the Dispatcher Database */
112 
113  /* Save the Previous State */
114  PreviousState = Mutant->Header.SignalState;
115 
116  /* Check if it is to be abandonned */
117  if (Abandon == FALSE)
118  {
119  /* Make sure that the Owner Thread is the current Thread */
120  if (Mutant->OwnerThread != CurrentThread)
121  {
122  /* Release the lock */
124 
125  /* Raise an exception */
126  ExRaiseStatus(Mutant->Abandoned ? STATUS_ABANDONED :
128  }
129 
130  /* If the thread owns it, then increase the signal state */
131  Mutant->Header.SignalState++;
132  }
133  else
134  {
135  /* It's going to be abandonned */
136  Mutant->Header.SignalState = 1;
137  Mutant->Abandoned = TRUE;
138  }
139 
140  /* Check if the signal state is only single */
141  if (Mutant->Header.SignalState == 1)
142  {
143  /* Check if it's below 0 now */
144  if (PreviousState <= 0)
145  {
146  /* Remove the mutant from the list */
147  RemoveEntryList(&Mutant->MutantListEntry);
148 
149  /* Save if we need to re-enable APCs */
150  EnableApc = Mutant->ApcDisable;
151  }
152 
153  /* Remove the Owning Thread and wake it */
154  Mutant->OwnerThread = NULL;
155 
156  /* Check if the Wait List isn't empty */
157  if (!IsListEmpty(&Mutant->Header.WaitListHead))
158  {
159  /* Wake the Mutant */
160  KiWaitTest(&Mutant->Header, Increment);
161  }
162  }
163 
164  /* Check if the caller wants to wait after this release */
165  if (Wait == FALSE)
166  {
167  /* Release the Lock */
169  }
170  else
171  {
172  /* Set a wait */
173  CurrentThread->WaitNext = TRUE;
174  CurrentThread->WaitIrql = OldIrql;
175  }
176 
177  /* Check if we need to re-enable APCs */
178  if (EnableApc) KeLeaveCriticalRegion();
179 
180  /* Return the previous state */
181  return PreviousState;
182 }
183 
184 /*
185  * @implemented
186  */
187 LONG
188 NTAPI
190  IN BOOLEAN Wait)
191 {
193 
194  /* There's no difference at this level between the two */
195  return KeReleaseMutant(Mutex, 1, FALSE, Wait);
196 }
197 
198 /* EOF */
#define ASSERT_IRQL_LESS_OR_EQUAL(x)
Definition: debug.h:251
struct _KMUTANT KMUTANT
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
VOID NTAPI KeInitializeMutant(IN PKMUTANT Mutant, IN BOOLEAN InitialOwner)
Definition: mutex.c:22
#define ExRaiseStatus
Definition: ntoskrnl.h:95
struct _KMUTANT KMUTEX
VOID FASTCALL KiWaitTest(PVOID Object, KPRIORITY Increment)
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:55
#define InsertTailList(ListHead, Entry)
LONG NTAPI KeReleaseMutex(IN PKMUTEX Mutex, IN BOOLEAN Wait)
Definition: mutex.c:189
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
#define STATUS_MUTANT_NOT_OWNED
Definition: ntstatus.h:292
LONG KPRIORITY
Definition: compat.h:454
Definition: Mutex.h:15
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
UCHAR KIRQL
Definition: env_spec_w32.h:591
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
long LONG
Definition: pedump.c:60
ULONG WaitNext
Definition: ketypes.h:1586
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
LONG NTAPI KeReleaseMutant(IN PKMUTANT Mutant, IN KPRIORITY Increment, IN BOOLEAN Abandon, IN BOOLEAN Wait)
Definition: mutex.c:98
#define ASSERT_MUTANT(Object)
VOID NTAPI KeInitializeMutex(IN PKMUTEX Mutex, IN ULONG Level)
Definition: mutex.c:67
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
LONG NTAPI KeReadStateMutant(IN PKMUTANT Mutant)
Definition: mutex.c:87
_In_ PLARGE_INTEGER _In_opt_ PTIMER_APC_ROUTINE _In_opt_ PVOID _In_ BOOLEAN _In_opt_ LONG _Out_opt_ PBOOLEAN PreviousState
Definition: zwfuncs.h:428
#define KeLeaveCriticalRegion()
Definition: ke_x.h:114
FORCEINLINE VOID KiReleaseDispatcherLock(IN KIRQL OldIrql)
Definition: ke_x.h:152
FORCEINLINE KIRQL KiAcquireDispatcherLock(VOID)
Definition: ke_x.h:144
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
unsigned int ULONG
Definition: retypes.h:1
#define KeGetCurrentThread
Definition: hal.h:44
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG Increment
Definition: CrNtStubs.h:42
#define STATUS_ABANDONED
Definition: ntstatus.h:75
_In_ BOOLEAN InitialOwner
Definition: kefuncs.h:590
LIST_ENTRY MutantListHead
Definition: ketypes.h:1899
KIRQL WaitIrql
Definition: ketypes.h:1685
IN BOOLEAN Wait
Definition: fatprocs.h:1529