ReactOS  0.4.14-dev-50-g13bb5e2
lock.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1990 - 1998
4 
5 Module Name:
6 
7  lock.c
8 
9 Abstract:
10 
11  This is the NT SCSI port driver.
12 
13 Environment:
14 
15  kernel mode only
16 
17 Notes:
18 
19  This module is a driver dll for scsi miniports.
20 
21 Revision History:
22 
23 --*/
24 
25 #include "classp.h"
26 
30 
31 //
32 // Structure used for tracking remove lock allocations in checked builds
33 //
34 typedef struct _REMOVE_TRACKING_BLOCK {
41 
42 
43 /*++////////////////////////////////////////////////////////////////////////////
44 
45 ClassAcquireRemoveLockEx()
46 
47 Routine Description:
48 
49  This routine is called to acquire the remove lock on the device object.
50  While the lock is held, the caller can assume that no pending pnp REMOVE
51  requests will be completed.
52 
53  The lock should be acquired immediately upon entering a dispatch routine.
54  It should also be acquired before creating any new reference to the
55  device object if there's a chance of releasing the reference before the
56  new one is done.
57 
58  This routine will return TRUE if the lock was successfully acquired or
59  FALSE if it cannot be because the device object has already been removed.
60 
61 Arguments:
62 
63  DeviceObject - the device object to lock
64 
65  Tag - Used for tracking lock allocation and release. If an irp is
66  specified when acquiring the lock then the same Tag must be
67  used to release the lock before the Tag is completed.
68 
69 Return Value:
70 
71  The value of the IsRemoved flag in the device extension. If this is
72  non-zero then the device object has received a Remove irp and non-cleanup
73  IRP's should fail.
74 
75  If the value is REMOVE_COMPLETE, the caller should not even release the
76  lock.
77 
78 --*/
79 ULONG
80 NTAPI
84  IN PCSTR File,
85  IN ULONG Line
86  )
87 {
89  LONG lockValue;
90 
91 
92 
93  //
94  // Grab the remove lock
95  //
96  lockValue = InterlockedIncrement(&commonExtension->RemoveLock);
97 
98  #if DBG
99 
100  DebugPrint((ClassDebugRemoveLock, "ClassAcquireRemoveLock: "
101  "Acquired for Object %p & irp %p - count is %d\n",
102  DeviceObject, Tag, lockValue));
103 
104  ASSERTMSG("ClassAcquireRemoveLock - lock value was negative : ",
105  (lockValue > 0));
106 
107  ASSERTMSG("RemoveLock increased to meet LockHighWatermark",
108  ((LockHighWatermark == 0) ||
109  (lockValue != LockHighWatermark)));
110 
111  if (commonExtension->IsRemoved != REMOVE_COMPLETE){
112  PREMOVE_TRACKING_BLOCK trackingBlock;
113 
114  trackingBlock = ExAllocatePool(NonPagedPool,
115  sizeof(REMOVE_TRACKING_BLOCK));
116 
117  if(trackingBlock == NULL) {
118 
119  KIRQL oldIrql;
120 
121  KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
122  &oldIrql);
123 
124  commonExtension->RemoveTrackingUntrackedCount++;
125 
126  DebugPrint((ClassDebugWarning, ">>>>>ClassAcquireRemoveLock: "
127  "Cannot track Tag %p - currently %d untracked requests\n",
128  Tag, commonExtension->RemoveTrackingUntrackedCount));
129 
130  KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock,
131  oldIrql);
132  }
133  else {
134  PREMOVE_TRACKING_BLOCK *removeTrackingList =
135  (PREMOVE_TRACKING_BLOCK*)&commonExtension->RemoveTrackingList;
136 
137  KIRQL oldIrql;
138 
139  trackingBlock->Tag = Tag;
140 
141  trackingBlock->File = File;
142  trackingBlock->Line = Line;
143 
144  KeQueryTickCount((&trackingBlock->TimeLocked));
145 
146  KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
147  &oldIrql);
148 
149  while(*removeTrackingList != NULL) {
150 
151  if((*removeTrackingList)->Tag > Tag) {
152  break;
153  }
154 
155  if((*removeTrackingList)->Tag == Tag) {
156 
157  DebugPrint((ClassDebugError, ">>>>>ClassAcquireRemoveLock: "
158  "already tracking Tag %p\n", Tag));
159  DebugPrint((ClassDebugError, ">>>>>ClassAcquireRemoveLock: "
160  "acquired in file %s on line %d\n",
161  (*removeTrackingList)->File,
162  (*removeTrackingList)->Line));
163  ASSERT(FALSE);
164  }
165 
166  removeTrackingList = &((*removeTrackingList)->NextBlock);
167  }
168 
169  trackingBlock->NextBlock = *removeTrackingList;
170  *removeTrackingList = trackingBlock;
171 
172  KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock,
173  oldIrql);
174 
175  }
176  }
177 
178  #endif
179 
180  return (commonExtension->IsRemoved);
181 }
182 
183 /*++////////////////////////////////////////////////////////////////////////////
184 
185 ClassReleaseRemoveLock()
186 
187 Routine Description:
188 
189  This routine is called to release the remove lock on the device object. It
190  must be called when finished using a previously locked reference to the
191  device object. If an Tag was specified when acquiring the lock then the
192  same Tag must be specified when releasing the lock.
193 
194  When the lock count reduces to zero, this routine will signal the waiting
195  remove Tag to delete the device object. As a result the DeviceObject
196  pointer should not be used again once the lock has been released.
197 
198 Arguments:
199 
200  DeviceObject - the device object to lock
201 
202  Tag - The irp (if any) specified when acquiring the lock. This is used
203  for lock tracking purposes
204 
205 Return Value:
206 
207  none
208 
209 --*/
210 VOID
211 NTAPI
215  )
216 {
218  LONG lockValue;
219 
220  #if DBG
221  PREMOVE_TRACKING_BLOCK *listEntry =
222  (PREMOVE_TRACKING_BLOCK*)&commonExtension->RemoveTrackingList;
223 
224  BOOLEAN found = FALSE;
225 
227 
228  BOOLEAN isRemoved = (commonExtension->IsRemoved == REMOVE_COMPLETE);
229 
230  KIRQL oldIrql;
231 
232  if(isRemoved) {
233  DBGTRAP(("ClassReleaseRemoveLock: REMOVE_COMPLETE set; this should never happen"));
234  InterlockedDecrement(&(commonExtension->RemoveLock));
235  return;
236  }
237 
238  //
239  // Check the tick count and make sure this thing hasn't been locked
240  // for more than MaxLockedMinutes.
241  //
242 
243  maxCount = KeQueryTimeIncrement() * 10; // microseconds
244  maxCount *= 1000; // milliseconds
245  maxCount *= 1000; // seconds
246  maxCount *= 60; // minutes
248 
249  DebugPrint((ClassDebugRemoveLock, "ClassReleaseRemoveLock: "
250  "maxCount = %0I64x\n", maxCount));
251 
252  KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
253  &oldIrql);
254 
255  while(*listEntry != NULL) {
256 
258  LARGE_INTEGER difference;
259 
260  block = *listEntry;
261 
262  KeQueryTickCount((&difference));
263 
264  difference.QuadPart -= block->TimeLocked.QuadPart;
265 
266  DebugPrint((ClassDebugRemoveLock, "ClassReleaseRemoveLock: "
267  "Object %p (tag %p) locked for %I64d ticks\n",
268  DeviceObject, block->Tag, difference.QuadPart));
269 
270  if(difference.QuadPart >= maxCount) {
271 
272  DebugPrint((ClassDebugError, ">>>>>ClassReleaseRemoveLock: "
273  "Object %p (tag %p) locked for %I64d ticks - TOO LONG\n",
274  DeviceObject, block->Tag, difference.QuadPart));
275  DebugPrint((ClassDebugError, ">>>>>ClassReleaseRemoveLock: "
276  "Lock acquired in file %s on line %d\n",
277  block->File, block->Line));
278  ASSERT(FALSE);
279  }
280 
281  if((found == FALSE) && ((*listEntry)->Tag == Tag)) {
282 
283  *listEntry = block->NextBlock;
284  ExFreePool(block);
285  found = TRUE;
286 
287  } else {
288 
289  listEntry = &((*listEntry)->NextBlock);
290 
291  }
292  }
293 
294  if(!found) {
295  if(commonExtension->RemoveTrackingUntrackedCount == 0) {
296  DebugPrint((ClassDebugError, ">>>>>ClassReleaseRemoveLock: "
297  "Couldn't find Tag %p in the lock tracking list\n",
298  Tag));
299  ASSERT(FALSE);
300  } else {
301  DebugPrint((ClassDebugError, ">>>>>ClassReleaseRemoveLock: "
302  "Couldn't find Tag %p in the lock tracking list - "
303  "may be one of the %d untracked requests still "
304  "outstanding\n",
305  Tag,
306  commonExtension->RemoveTrackingUntrackedCount));
307 
308  commonExtension->RemoveTrackingUntrackedCount--;
309  ASSERT(commonExtension->RemoveTrackingUntrackedCount >= 0);
310  }
311  }
312 
313  KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock,
314  oldIrql);
315 
316  #endif
317 
318  lockValue = InterlockedDecrement(&commonExtension->RemoveLock);
319 
320  DebugPrint((ClassDebugRemoveLock, "ClassReleaseRemoveLock: "
321  "Released for Object %p & irp %p - count is %d\n",
322  DeviceObject, Tag, lockValue));
323 
324  ASSERT(lockValue >= 0);
325 
326  ASSERTMSG("RemoveLock decreased to meet LockLowWatermark",
327  ((LockLowWatermark == 0) || !(lockValue == LockLowWatermark)));
328 
329  if(lockValue == 0) {
330 
331  ASSERT(commonExtension->IsRemoved);
332 
333  //
334  // The device needs to be removed. Signal the remove event
335  // that it's safe to go ahead.
336  //
337 
338  DebugPrint((ClassDebugRemoveLock, "ClassReleaseRemoveLock: "
339  "Release for object %p & irp %p caused lock to go to zero\n",
340  DeviceObject, Tag));
341 
342  KeSetEvent(&commonExtension->RemoveEvent,
344  FALSE);
345 
346  }
347  return;
348 }
349 
350 /*++////////////////////////////////////////////////////////////////////////////
351 
352 ClassCompleteRequest()
353 
354 Routine Description:
355 
356  This routine is a wrapper around (and should be used instead of)
357  IoCompleteRequest. It is used primarily for debugging purposes.
358  The routine will assert if the Irp being completed is still holding
359  the release lock.
360 
361 Arguments:
362 
363  DeviceObject - the device object that was handling this request
364 
365  Irp - the irp to be completed by IoCompleteRequest
366 
367  PriorityBoost - the priority boost to pass to IoCompleteRequest
368 
369 Return Value:
370 
371  none
372 
373 --*/
374 VOID
375 NTAPI
378  IN PIRP Irp,
380  )
381 {
382 
383  #if DBG
385  PREMOVE_TRACKING_BLOCK *listEntry =
386  (PREMOVE_TRACKING_BLOCK*)&commonExtension->RemoveTrackingList;
387 
388  KIRQL oldIrql;
389 
390  KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
391  &oldIrql);
392 
393  while(*listEntry != NULL) {
394 
395  if((*listEntry)->Tag == Irp) {
396  break;
397  }
398 
399  listEntry = &((*listEntry)->NextBlock);
400  }
401 
402  if(*listEntry != NULL) {
403 
404  DebugPrint((ClassDebugError, ">>>>>ClassCompleteRequest: "
405  "Irp %p completed while still holding the remove lock\n",
406  Irp));
407  DebugPrint((ClassDebugError, ">>>>>ClassCompleteRequest: "
408  "Lock acquired in file %s on line %d\n",
409  (*listEntry)->File, (*listEntry)->Line));
410  ASSERT(FALSE);
411  }
412 
413  KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock, oldIrql);
414  #endif
415 
417  return;
418 } // end ClassCompleteRequest()
419 
static unsigned int block
Definition: xmlmemory.c:118
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
LONG LockHighWatermark
Definition: lock.c:27
#define REMOVE_COMPLETE
Definition: classpnp.h:95
LONG MaxLockedMinutes
Definition: lock.c:29
_In_ PIRP Irp
Definition: csq.h:116
ULONG NTAPI KeQueryTimeIncrement(VOID)
Definition: clock.c:153
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
ULONG NTAPI ClassAcquireRemoveLockEx(IN PDEVICE_OBJECT DeviceObject, IN OPTIONAL PVOID Tag, IN PCSTR File, IN ULONG Line)
Definition: lock.c:81
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
#define ASSERTMSG(msg, exp)
Definition: nt_native.h:431
#define DBGTRAP(args_in_parens)
Definition: debug.h:137
_In_ CCHAR PriorityBoost
Definition: iofuncs.h:763
PVOID DeviceExtension
Definition: env_spec_w32.h:418
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define IoCompleteRequest
Definition: irp.c:1240
VOID NTAPI KeQueryTickCount(IN PLARGE_INTEGER TickCount)
Definition: clock.c:165
LONG LockLowWatermark
Definition: lock.c:28
int64_t LONGLONG
Definition: typedefs.h:66
char CCHAR
Definition: typedefs.h:50
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
struct _REMOVE_TRACKING_BLOCK * NextBlock
Definition: lock.c:35
LARGE_INTEGER TimeLocked
Definition: lock.c:37
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
Definition: ncftp.h:79
#define InterlockedDecrement
Definition: armddk.h:52
#define ExAllocatePool(type, size)
Definition: fbtusb.h:44
ULONG NTAPI DebugPrint(IN PSTRING DebugString, IN ULONG ComponentId, IN ULONG Level)
Definition: debug.c:23
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
VOID NTAPI ClassCompleteRequest(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN CCHAR PriorityBoost)
Definition: lock.c:376
#define InterlockedIncrement
Definition: armddk.h:53
GLsizei maxCount
Definition: glext.h:6042
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
IN ULONG IN ULONG Tag
Definition: evtlib.h:159
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:566
struct _REMOVE_TRACKING_BLOCK * PREMOVE_TRACKING_BLOCK
const char * PCSTR
Definition: typedefs.h:51
Definition: File.h:15
KSPIN_LOCK RemoveTrackingSpinlock
Definition: classpnp.h:579
struct _REMOVE_TRACKING_BLOCK REMOVE_TRACKING_BLOCK
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
LONGLONG QuadPart
Definition: typedefs.h:112
VOID NTAPI ClassReleaseRemoveLock(IN PDEVICE_OBJECT DeviceObject, IN OPTIONAL PIRP Tag)
Definition: lock.c:212
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68