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.

421 lines
11 KiB

  1. #include "wdmsys.h"
  2. #pragma LOCKED_CODE
  3. #pragma LOCKED_DATA
  4. //
  5. // Robust checking enables bugchecks in the retail version of this component.
  6. //
  7. BOOL gbRobustChecking = FALSE;
  8. #if 0
  9. //
  10. // PagedCode: This routine should be used in routines that touch pageable
  11. // code and data. Notice that this is not the PAGED_CODE() macro so that it
  12. // will be in the retail code.
  13. //
  14. void
  15. PagedCode(
  16. void
  17. )
  18. {
  19. if( KeGetCurrentIrql() > APC_LEVEL )
  20. {
  21. KeBugCheckEx(AUDIO_BUGCHECK_CODE,AUDIO_NOT_BELOW_DISPATCH_LEVEL,0,0,0);
  22. }
  23. }
  24. void
  25. ValidatePassiveLevel(
  26. void
  27. )
  28. {
  29. if( KeGetCurrentIrql() != PASSIVE_LEVEL )
  30. {
  31. KeBugCheckEx(AUDIO_BUGCHECK_CODE,AUDIO_NOT_AT_PASSIVE_LEVEL,0,0,0);
  32. }
  33. }
  34. //
  35. // If bExclusive is TRUE, the caller wants to know if the mutex is acquired multiple
  36. // times on the same thread. If they don't want this checking done, they should
  37. // set bExclusive to FALSE.
  38. //
  39. NTSTATUS
  40. AudioEnterMutex(
  41. IN PKMUTEX pmutex,
  42. IN BOOL bExclusive
  43. )
  44. {
  45. PRKTHREAD pkt;
  46. NTSTATUS Status;
  47. LONG lMutexState;
  48. Status = KeWaitForSingleObject ( pmutex,Executive,KernelMode,FALSE,NULL ) ;
  49. if( gbRobustChecking && bExclusive )
  50. {
  51. //
  52. // After entering the mutex, we sanity check our nested count, but we
  53. // only do this if we need to. If the caller said that they designed the
  54. // code only for exclusive access, we'll bugcheck if we get nested.
  55. //
  56. if( (lMutexState = KeReadStateMutex(pmutex)) < 0 )
  57. {
  58. //
  59. // Every time you acquire a mutex the state will be decremented. 1 means
  60. // that it's available, 0 means it's held, -1 means this is the second time
  61. // it's acquired, -2 means it's the third and so on. Thus, if we're nested
  62. // on this thread, we'll end up here.
  63. //
  64. KeBugCheckEx(AUDIO_BUGCHECK_CODE,
  65. AUDIO_NESTED_MUTEX_SITUATION,
  66. (ULONG_PTR)pmutex,
  67. lMutexState,
  68. 0);
  69. }
  70. }
  71. return Status;
  72. }
  73. //
  74. // This routine yields if we're at PASSIVE_LEVEL
  75. //
  76. void
  77. AudioPerformYield(
  78. void
  79. )
  80. {
  81. PRKTHREAD pthrd;
  82. KPRIORITY kpriority;
  83. //
  84. // After releasing the mutex we want to yield execution to all other threads
  85. // on the machine to try to expose preemption windows.
  86. //
  87. if( ( gbRobustChecking ) &&
  88. ( KeGetCurrentIrql() == PASSIVE_LEVEL ) )
  89. {
  90. if( (pthrd = KeGetCurrentThread()) )
  91. {
  92. kpriority = KeQueryPriorityThread(KeGetCurrentThread());
  93. //
  94. // Lower this thrread's priority so another thread will
  95. // get scheduled.
  96. //
  97. KeSetPriorityThread(pthrd,1); // Is that low enough?
  98. //
  99. // This might be overkill, but yield.
  100. //
  101. ZwYieldExecution();
  102. //
  103. // Now restore the priority for this thread and party on.
  104. //
  105. KeSetPriorityThread(pthrd,kpriority);
  106. }
  107. }
  108. }
  109. void
  110. AudioLeaveMutex(
  111. IN PKMUTEX pmutex
  112. )
  113. {
  114. PRKTHREAD pthrd;
  115. KPRIORITY kpriority;
  116. KeReleaseMutex ( pmutex, FALSE ) ;
  117. AudioPerformYield();
  118. }
  119. NTSTATUS
  120. AudioIoCallDriver (
  121. IN PDEVICE_OBJECT pDevice,
  122. IN PIRP pIrp
  123. )
  124. {
  125. NTSTATUS Status;
  126. Status = IoCallDriver(pDevice,pIrp);
  127. AudioPerformYield();
  128. return Status;
  129. }
  130. void
  131. AudioEnterSpinLock(
  132. IN PKSPIN_LOCK pSpinLock,
  133. OUT PKIRQL pOldIrql
  134. )
  135. {
  136. //
  137. // KeAcquireSpinLock can only be called less then or equal to dispatch level.
  138. // let's verify that here.
  139. //
  140. if( ( gbRobustChecking ) &&
  141. ( KeGetCurrentIrql() > DISPATCH_LEVEL ) )
  142. {
  143. KeBugCheckEx(AUDIO_BUGCHECK_CODE,
  144. AUDIO_INVALID_IRQL_LEVEL,
  145. 0,
  146. 0,
  147. 0);
  148. }
  149. KeAcquireSpinLock ( pSpinLock, pOldIrql ) ;
  150. }
  151. void
  152. AudioLeaveSpinLock(
  153. IN PKSPIN_LOCK pSpinLock,
  154. IN KIRQL OldIrql
  155. )
  156. {
  157. KeReleaseSpinLock ( pSpinLock, OldIrql ) ;
  158. AudioPerformYield();
  159. }
  160. void
  161. AudioObDereferenceObject(
  162. IN PVOID pvObject
  163. )
  164. {
  165. ObDereferenceObject(pvObject);
  166. AudioPerformYield();
  167. }
  168. void
  169. AudioIoCompleteRequest(
  170. IN PIRP pIrp,
  171. IN CCHAR PriorityBoost
  172. )
  173. {
  174. IoCompleteRequest(pIrp,PriorityBoost);
  175. AudioPerformYield();
  176. }
  177. #endif
  178. #define MEMORY_LIMIT_CHECK 262144
  179. //
  180. // This routine assumes that pptr points to a memory location that currently
  181. // contains a NULL value. Thus, on failure, this routine does not have to
  182. // write back a NULL value.
  183. //
  184. // Entry:
  185. // if dwFlags contains:
  186. //#define DEFAULT_MEMORY 0x00 // Standard ExAllocatePool call
  187. //#define ZERO_FILL_MEMORY 0x01 // Zero the memory
  188. //#define QUOTA_MEMORY 0x02 // ExAllocatePoolWithQuota call
  189. //#define LIMIT_MEMORY 0x04 // Never allocation more then 1/4 Meg
  190. //#define FIXED_MEMORY 0x08 // Use locked memory
  191. //#define PAGED_MEMORY 0x10 // use pageable memory
  192. //
  193. NTSTATUS
  194. AudioAllocateMemory(
  195. IN SIZE_T bytes,
  196. IN ULONG tag,
  197. IN AAMFLAGS dwFlags,
  198. OUT PVOID *pptr
  199. )
  200. {
  201. NTSTATUS Status;
  202. POOL_TYPE pooltype;
  203. PVOID pInit;
  204. KIRQL irql;
  205. PVOID ptr = NULL;
  206. ASSERT(*pptr == NULL);
  207. if( 0 == bytes )
  208. {
  209. //
  210. // The code should never be asking for zero bytes. The core will bugcheck
  211. // on a call like this. In debug mode we'll assert. In retail, we'll
  212. // return an error.
  213. //
  214. ASSERT(0);
  215. Status = STATUS_INSUFFICIENT_RESOURCES;
  216. } else {
  217. if( dwFlags & FIXED_MEMORY )
  218. pooltype = NonPagedPool;
  219. else
  220. pooltype = PagedPool;
  221. //
  222. // Allocating pageable memory at DISPATCH_LEVEL is a bad thing to do.
  223. // here we make sure that is not the case.
  224. //
  225. if( ( (irql = KeGetCurrentIrql()) > DISPATCH_LEVEL ) ||
  226. ((DISPATCH_LEVEL == irql ) && (NonPagedPool != pooltype)) )
  227. {
  228. //
  229. // Either way, we've got an error, bugcheck or exit.
  230. //
  231. if( gbRobustChecking )
  232. {
  233. KeBugCheckEx(AUDIO_BUGCHECK_CODE,AUDIO_INVALID_IRQL_LEVEL,0,0,0);
  234. } else {
  235. //
  236. // If we can't bugcheck, then we're going to return an error
  237. // in this case.
  238. //
  239. Status = STATUS_INSUFFICIENT_RESOURCES;
  240. goto exit;
  241. }
  242. }
  243. //
  244. // Let's see if the caller has asked to limit the allocation to a "reasonable"
  245. // number of bytes. If so, "reasonable" is 1/4 meg.
  246. //
  247. if( ( dwFlags & LIMIT_MEMORY ) && ( bytes > MEMORY_LIMIT_CHECK ) )
  248. {
  249. //
  250. // For some reason, this allocation is trying to allocate more then was designed.
  251. // Why is the caller allocating so much?
  252. //
  253. if( gbRobustChecking )
  254. KeBugCheckEx(AUDIO_BUGCHECK_CODE,AUDIO_ABSURD_ALLOCATION_ATTEMPTED,0,0,0);
  255. //
  256. // Checked build will assert if robust checking is not enabled.
  257. //
  258. ASSERT("Memory Allocation Unreasonable!");
  259. }
  260. //
  261. // Allocate the memory, NULL is returned on failure in the normal case, an exception
  262. // is raised with quota. ptr is NULLed out above for the Quota routine.
  263. //
  264. if( dwFlags & QUOTA_MEMORY )
  265. {
  266. //
  267. // Caller wants to charge the allocation to the current user context.
  268. //
  269. try
  270. {
  271. ptr = ExAllocatePoolWithQuotaTag(pooltype,bytes,tag);
  272. }except (EXCEPTION_EXECUTE_HANDLER) {
  273. Status = STATUS_INSUFFICIENT_RESOURCES;
  274. }
  275. } else {
  276. //
  277. // Don't want to assign this memory to the quota.
  278. //
  279. ptr = ExAllocatePoolWithTag(pooltype, bytes, tag);
  280. }
  281. if( ptr )
  282. {
  283. if( dwFlags & ZERO_FILL_MEMORY )
  284. {
  285. RtlFillMemory( ptr,bytes,0 );
  286. }
  287. //
  288. // Never allocate over the top of an existing pointer. Interlock exchange
  289. // with the location. This interlock updates the location in the caller.
  290. //
  291. if( pInit = InterlockedExchangePointer(pptr,ptr) )
  292. {
  293. //
  294. // If we get a return value from this exchange it means that there
  295. // was already a pointer in the location that we added a pointer too.
  296. // If this is the case, most likely we overwrote a valid memory
  297. // pointer. With robust checking we don't want this to happen.
  298. //
  299. if( gbRobustChecking )
  300. {
  301. KeBugCheckEx(AUDIO_BUGCHECK_CODE,
  302. AUDIO_MEMORY_ALLOCATION_OVERWRITE,
  303. (ULONG_PTR)pInit,
  304. 0,0);
  305. }
  306. //
  307. // If we end up here, we've overwritten a memory pointer with a
  308. // successful memory allocation. Or ASSERT at the top of this
  309. // function should have fired. In any case, we can return success
  310. // and how that nothing bad happens.
  311. //
  312. }
  313. Status = STATUS_SUCCESS;
  314. } else {
  315. //
  316. // Our memory allocation failed. *pptr should still be NULL
  317. // return error.
  318. //
  319. Status = STATUS_INSUFFICIENT_RESOURCES;
  320. }
  321. }
  322. exit:
  323. return Status;
  324. }
  325. //
  326. // This routine is safe to call with a NULL memory pointer. It will return
  327. // STATUS_UNSUCCESSFUL and do nothing if passed a NULL pointer. Also, this routine
  328. // reads the location atomically so it should be safe in a multiproc environment.
  329. //
  330. void
  331. AudioFreeMemory(
  332. IN SIZE_T bytes,
  333. IN OUT PVOID *pptr
  334. )
  335. {
  336. PVOID pFree;
  337. KIRQL irql;
  338. //
  339. // Interlockedexhchange the pointer will NULL, validate that it's non-NULL
  340. // trash the memory if needed and then free the pointer.
  341. //
  342. pFree = InterlockedExchangePointer(pptr,NULL);
  343. if( pFree )
  344. {
  345. //
  346. // We have a pointer to free.
  347. //
  348. if( gbRobustChecking )
  349. {
  350. //
  351. // The docs say that we need to be careful how we call the free routine
  352. // with regard to IRQlevel. Thus, if we're being robust we'll do this
  353. // extra work.
  354. //
  355. if( (irql = KeGetCurrentIrql()) > DISPATCH_LEVEL )
  356. {
  357. KeBugCheckEx(AUDIO_BUGCHECK_CODE,AUDIO_INVALID_IRQL_LEVEL,0,0,0);
  358. }
  359. //
  360. // Under debug we're going to put 'k's in the memory location in order
  361. // to make extra sure that no one is using this memory.
  362. //
  363. if( UNKNOWN_SIZE != bytes )
  364. {
  365. RtlFillMemory( pFree,bytes,'k' );
  366. }
  367. }
  368. //
  369. // Now we actually free the memory.
  370. //
  371. ExFreePool(pFree);
  372. }
  373. return;
  374. }