Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

385 lines
8.7 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. remlock.c
  5. Abstract:
  6. This is the NT SCSI port driver.
  7. Authors:
  8. Peter Wieland
  9. Kenneth Ray
  10. Environment:
  11. kernel mode only
  12. Notes:
  13. This module is a driver dll for scsi miniports.
  14. Revision History:
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <ntos.h>
  19. #include <remlock.h>
  20. #define MinutesToTicks(x) \
  21. (ULONGLONG) KeQueryTimeIncrement() * \
  22. 10 * \
  23. 1000 * \
  24. 1000 * \
  25. 60 * \
  26. x
  27. // 10 -> microseconds, 1000 -> miliseconds, 1000 -> seconds, 60 -> minutes
  28. // LIST_ENTRY RtlpRemoveLockList;
  29. NTSYSAPI
  30. PRTL_REMOVE_LOCK
  31. NTAPI
  32. RtlAllocateRemoveLock(
  33. IN ULONG MaxLockedMinutes,
  34. IN ULONG AllocateTag,
  35. IN ULONG HighWatermark
  36. )
  37. /*++
  38. Routine Description:
  39. This routine is called to initialize the remove lock for a device object.
  40. --*/
  41. {
  42. PRTL_REMOVE_LOCK lock;
  43. lock = ExAllocatePoolWithTag (NonPagedPool,
  44. sizeof (RTL_REMOVE_LOCK),
  45. AllocateTag);
  46. if (lock) {
  47. lock->Signature = RTL_REMOVE_LOCK_SIG;
  48. lock->Removed = FALSE;
  49. lock->IoCount = 1;
  50. KeInitializeEvent(&lock->RemoveEvent, SynchronizationEvent, FALSE);
  51. #if DBG
  52. lock->HighWatermark = HighWatermark;
  53. lock->MaxLockedMinutes = MaxLockedMinutes;
  54. lock->AllocateTag = AllocateTag;
  55. KeInitializeSpinLock (&lock->Spin);
  56. lock->Blocks.Link = NULL;
  57. #endif
  58. }
  59. return lock;
  60. }
  61. NTSYSAPI
  62. NTSTATUS
  63. NTAPI
  64. RtlAcquireRemoveLockEx(
  65. IN PRTL_REMOVE_LOCK RemoveLock,
  66. IN OPTIONAL PVOID Tag,
  67. IN PCSTR File,
  68. IN ULONG Line
  69. )
  70. /*++
  71. Routine Description:
  72. This routine is called to acquire the remove lock for a device object.
  73. While the lock is held, the caller can assume that no pending pnp REMOVE
  74. requests will be completed.
  75. The lock should be acquired immediately upon entering a dispatch routine.
  76. It should also be acquired before creating any new reference to the
  77. device object if there's a chance of releasing the reference before the
  78. new one is done.
  79. Arguments:
  80. RemoveLock - A pointer to an initialized REMOVE_LOCK structure.
  81. Tag - Used for tracking lock allocation and release. If an irp is
  82. specified when acquiring the lock then the same Tag must be
  83. used to release the lock before the Tag is completed.
  84. File - set to __FILE__ as the location in the code where the lock was taken.
  85. Line - set to __LINE__.
  86. Return Value:
  87. Returns whether or not the remove lock was obtained.
  88. If successful the caller should continue with work calling
  89. RtlReleaseRemoveLock when finished.
  90. If not successful the lock was not obtained. The caller should abort the
  91. work but not call RtlReleaseRemoveLock.
  92. --*/
  93. {
  94. LONG lockValue;
  95. NTSTATUS status;
  96. #if DBG
  97. PRTL_REMOVE_LOCK_TRACKING_BLOCK trackingBlock;
  98. #endif
  99. //
  100. // Grab the remove lock
  101. //
  102. lockValue = InterlockedIncrement(&RemoveLock->IoCount);
  103. ASSERTMSG("RtlAcquireRemoveLock - lock value was negative : ",
  104. (lockValue > 0));
  105. ASSERTMSG("RemoveLock increased to meet LockHighWatermark",
  106. ((0 == RemoveLock->HighWatermark) ||
  107. (lockValue <= RemoveLock->HighWatermark)));
  108. if (! RemoveLock->Removed) {
  109. #if DBG
  110. trackingBlock = ExAllocatePoolWithTag(
  111. NonPagedPool,
  112. sizeof(RTL_REMOVE_LOCK_TRACKING_BLOCK),
  113. RemoveLock->AllocateTag);
  114. RtlZeroMemory (trackingBlock,
  115. sizeof (RTL_REMOVE_LOCK_TRACKING_BLOCK));
  116. if (NULL == trackingBlock) {
  117. ASSERTMSG ("insufficient resources", FALSE);
  118. } else {
  119. KIRQL oldIrql;
  120. trackingBlock->Tag = Tag;
  121. trackingBlock->File = File;
  122. trackingBlock->Line = Line;
  123. KeQueryTickCount(&trackingBlock->TimeLocked);
  124. KeAcquireSpinLock (&RemoveLock->Spin, &oldIrql);
  125. trackingBlock->Link = RemoveLock->Blocks.Link;
  126. RemoveLock->Blocks.Link = trackingBlock;
  127. KeReleaseSpinLock(&RemoveLock->Spin, oldIrql);
  128. }
  129. #endif
  130. status = STATUS_SUCCESS;
  131. } else {
  132. if (0 == InterlockedDecrement (&RemoveLock->IoCount)) {
  133. KeSetEvent (&RemoveLock->RemoveEvent, 0, FALSE);
  134. }
  135. status = STATUS_DELETE_PENDING;
  136. }
  137. return status;
  138. }
  139. NTSYSAPI
  140. VOID
  141. NTAPI
  142. RtlReleaseRemoveLock(
  143. IN PRTL_REMOVE_LOCK RemoveLock,
  144. IN PVOID Tag
  145. )
  146. /*++
  147. Routine Description:
  148. This routine is called to release the remove lock on the device object. It
  149. must be called when finished using a previously locked reference to the
  150. device object. If an Tag was specified when acquiring the lock then the
  151. same Tag must be specified when releasing the lock.
  152. When the lock count reduces to zero, this routine will signal the waiting
  153. event to release the waiting thread deleting the device object protected
  154. by this lock.
  155. Arguments:
  156. DeviceObject - the device object to lock
  157. Tag - The tag (if any) specified when acquiring the lock. This is used
  158. for lock tracking purposes
  159. Return Value:
  160. none
  161. --*/
  162. {
  163. LONG lockValue;
  164. #if DBG
  165. KIRQL oldIrql;
  166. LARGE_INTEGER difference;
  167. BOOLEAN found;
  168. LONGLONG maxTime;
  169. PRTL_REMOVE_LOCK_TRACKING_BLOCK last;
  170. PRTL_REMOVE_LOCK_TRACKING_BLOCK current;
  171. //
  172. // Check the tick count and make sure this thing hasn't been locked
  173. // for more than MaxLockedMinutes.
  174. //
  175. found = FALSE;
  176. KeAcquireSpinLock(&RemoveLock->Spin, &oldIrql);
  177. last = (&RemoveLock->Blocks);
  178. current = last->Link;
  179. //
  180. // Note the first one is the sentinal
  181. //
  182. while (NULL != current) {
  183. KeQueryTickCount((&difference));
  184. difference.QuadPart -= current->TimeLocked.QuadPart;
  185. maxTime = MinutesToTicks (RemoveLock->MaxLockedMinutes);
  186. if (maxTime && (maxTime < difference.QuadPart)) {
  187. KdPrint(("RtlReleaseRemoveLock: Lock %#08lx (tag %#08lx) locked "
  188. "for %I64d ticks - TOO LONG\n",
  189. RemoveLock,
  190. current->Tag,
  191. difference.QuadPart));
  192. KdPrint(("RtlReleaseRemoveLock: Lock acquired in file "
  193. "%s on line %d\n",
  194. current->File,
  195. current->Line));
  196. ASSERT(FALSE);
  197. }
  198. if ((!found) && (current->Tag == Tag)) {
  199. found = TRUE;
  200. last->Link = current->Link;
  201. ExFreePool (current);
  202. current = last->Link;
  203. continue;
  204. }
  205. last = current;
  206. current = current->Link;
  207. }
  208. KeReleaseSpinLock(&RemoveLock->Spin, oldIrql);
  209. if (!found) {
  210. KdPrint (("RtlReleaseRemoveLock: Couldn't find Tag %#08lx "
  211. "in the lock tracking list\n",
  212. Tag));
  213. ASSERT(FALSE);
  214. }
  215. #endif
  216. lockValue = InterlockedDecrement(&RemoveLock->IoCount);
  217. ASSERT(0 <= lockValue);
  218. if (0 == lockValue) {
  219. ASSERT (RemoveLock->Removed);
  220. //
  221. // The device needs to be removed. Signal the remove event
  222. // that it's safe to go ahead.
  223. //
  224. KeSetEvent(&RemoveLock->RemoveEvent,
  225. IO_NO_INCREMENT,
  226. FALSE);
  227. }
  228. return;
  229. }
  230. NTSYSAPI
  231. VOID
  232. NTAPI
  233. RtlReleaseRemoveLockAndWait (
  234. IN PRTL_REMOVE_LOCK RemoveLock,
  235. IN PVOID Tag
  236. )
  237. /*++
  238. Routine Description:
  239. This routine is called when the client would like to delete the remove-
  240. locked resource.
  241. This routine will block until all the remove locks have completed.
  242. This routine MUST be called after acquiring once more the lock.
  243. Arguments:
  244. RemoveLock -
  245. Return Value:
  246. none
  247. --*/
  248. {
  249. LONG ioCount;
  250. PAGED_CODE ();
  251. RemoveLock->Removed = TRUE;
  252. ioCount = InterlockedDecrement (&RemoveLock->IoCount);
  253. ASSERT (0 < ioCount);
  254. if (0 < InterlockedDecrement (&RemoveLock->IoCount)) {
  255. KeWaitForSingleObject (&RemoveLock->RemoveEvent,
  256. Executive,
  257. KernelMode,
  258. FALSE,
  259. NULL);
  260. }
  261. #if DBG
  262. ASSERT (RemoveLock->Blocks.Link);
  263. if (Tag != RemoveLock->Blocks.Link->Tag) {
  264. KdPrint (("RtlRelaseRemoveLockAndWait last tag invalid %x %x\n",
  265. Tag,
  266. RemoveLock->Blocks.Link->Tag));
  267. ASSERT (Tag != RemoveLock->Blocks.Link->Tag);
  268. }
  269. ExFreePool (RemoveLock->Blocks.Link);
  270. #endif
  271. }