Reimplemented dispatcher database lock and synchronization primitives.
[reactos.git] / reactos / ntoskrnl / ke / mutex.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: mutex.c,v 1.15 2003/11/02 01:15:15 ekohl Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ke/mutex.c
23 * PURPOSE: Implements mutex
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 * UPDATE HISTORY:
26 * Created 22/05/98
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <internal/ke.h>
33 #include <internal/ps.h>
34 #include <internal/id.h>
35
36 #include <internal/debug.h>
37
38 /* FUNCTIONS *****************************************************************/
39
40 /*
41 * @implemented
42 */
43 VOID STDCALL
44 KeInitializeMutex(IN PKMUTEX Mutex,
45 IN ULONG Level)
46 {
47 KeInitializeDispatcherHeader(&Mutex->Header,
48 InternalMutexType,
49 sizeof(KMUTEX) / sizeof(ULONG),
50 1);
51 Mutex->MutantListEntry.Flink = NULL;
52 Mutex->MutantListEntry.Blink = NULL;
53 Mutex->OwnerThread = NULL;
54 Mutex->Abandoned = FALSE;
55 Mutex->ApcDisable = 1;
56 }
57
58 /*
59 * @implemented
60 */
61 LONG STDCALL
62 KeReadStateMutex(IN PKMUTEX Mutex)
63 {
64 return(Mutex->Header.SignalState);
65 }
66
67 /*
68 * @implemented
69 */
70 LONG STDCALL
71 KeReleaseMutex(IN PKMUTEX Mutex,
72 IN BOOLEAN Wait)
73 {
74 KIRQL OldIrql;
75
76 OldIrql = KeAcquireDispatcherDatabaseLock();
77 if (Mutex->OwnerThread != KeGetCurrentThread())
78 {
79 DbgPrint("THREAD_NOT_MUTEX_OWNER: Mutex %p\n", Mutex);
80 KEBUGCHECK(0); /* THREAD_NOT_MUTEX_OWNER */
81 }
82 Mutex->Header.SignalState++;
83 assert(Mutex->Header.SignalState <= 1);
84 if (Mutex->Header.SignalState == 1)
85 {
86 Mutex->OwnerThread = NULL;
87 if (Mutex->MutantListEntry.Flink && Mutex->MutantListEntry.Blink)
88 RemoveEntryList(&Mutex->MutantListEntry);
89 KeDispatcherObjectWake(&Mutex->Header);
90 }
91
92 if (Wait == FALSE)
93 {
94 KeReleaseDispatcherDatabaseLock(OldIrql);
95 }
96 else
97 {
98 KTHREAD *Thread = KeGetCurrentThread();
99 Thread->WaitNext = Wait;
100 Thread->WaitIrql = OldIrql;
101 }
102
103 return(0);
104 }
105
106 /*
107 * @implemented
108 */
109 NTSTATUS STDCALL
110 KeWaitForMutexObject(IN PKMUTEX Mutex,
111 IN KWAIT_REASON WaitReason,
112 IN KPROCESSOR_MODE WaitMode,
113 IN BOOLEAN Alertable,
114 IN PLARGE_INTEGER Timeout)
115 {
116 return(KeWaitForSingleObject(Mutex,WaitReason,WaitMode,Alertable,Timeout));
117 }
118
119
120 /*
121 * @implemented
122 */
123 VOID STDCALL
124 KeInitializeMutant(IN PKMUTANT Mutant,
125 IN BOOLEAN InitialOwner)
126 {
127 if (InitialOwner == TRUE)
128 {
129 KeInitializeDispatcherHeader(&Mutant->Header,
130 InternalMutexType,
131 sizeof(KMUTANT) / sizeof(ULONG),
132 0);
133 InsertTailList(&KeGetCurrentThread()->MutantListHead,
134 &Mutant->MutantListEntry);
135 Mutant->OwnerThread = KeGetCurrentThread();
136 }
137 else
138 {
139 KeInitializeDispatcherHeader(&Mutant->Header,
140 InternalMutexType,
141 sizeof(KMUTANT) / sizeof(ULONG),
142 1);
143 Mutant->MutantListEntry.Flink = NULL;
144 Mutant->MutantListEntry.Blink = NULL;
145 Mutant->OwnerThread = NULL;
146 }
147 Mutant->Abandoned = FALSE;
148 Mutant->ApcDisable = 0;
149 }
150
151 /*
152 * @implemented
153 */
154 LONG STDCALL
155 KeReadStateMutant(IN PKMUTANT Mutant)
156 {
157 return(Mutant->Header.SignalState);
158 }
159
160 /*
161 * @implemented
162 */
163 LONG STDCALL
164 KeReleaseMutant(IN PKMUTANT Mutant,
165 IN KPRIORITY Increment,
166 IN BOOLEAN Abandon,
167 IN BOOLEAN Wait)
168 {
169 KIRQL OldIrql;
170
171 OldIrql = KeAcquireDispatcherDatabaseLock();
172 if (Abandon == FALSE)
173 {
174 if (Mutant->OwnerThread != NULL && Mutant->OwnerThread != KeGetCurrentThread())
175 {
176 DbgPrint("THREAD_NOT_MUTEX_OWNER: Mutant->OwnerThread %p CurrentThread %p\n",
177 Mutant->OwnerThread,
178 KeGetCurrentThread());
179 KEBUGCHECK(0); /* THREAD_NOT_MUTEX_OWNER */
180 }
181 Mutant->Header.SignalState++;
182 assert(Mutant->Header.SignalState <= 1);
183 }
184 else
185 {
186 if (Mutant->OwnerThread != NULL)
187 {
188 Mutant->Header.SignalState = 1;
189 Mutant->Abandoned = TRUE;
190 }
191 }
192
193 if (Mutant->Header.SignalState == 1)
194 {
195 Mutant->OwnerThread = NULL;
196 if (Mutant->MutantListEntry.Flink && Mutant->MutantListEntry.Blink)
197 RemoveEntryList(&Mutant->MutantListEntry);
198 KeDispatcherObjectWake(&Mutant->Header);
199 }
200
201 if (Wait == FALSE)
202 {
203 KeReleaseDispatcherDatabaseLock(OldIrql);
204 }
205 else
206 {
207 KTHREAD *Thread = KeGetCurrentThread();
208 Thread->WaitNext = Wait;
209 Thread->WaitIrql = OldIrql;
210 }
211
212 return(0);
213 }
214
215 /* EOF */