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.

1700 lines
43 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. prefparm.c
  5. Abstract:
  6. This module contains the code for prefetcher parameter handling.
  7. Author:
  8. Cenk Ergan (cenke) 15-Mar-2000
  9. Revision History:
  10. --*/
  11. #include "cc.h"
  12. #include "zwapi.h"
  13. #include "prefetch.h"
  14. #include "preftchp.h"
  15. #include "stdio.h"
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(INIT, CcPfParametersInitialize)
  18. #pragma alloc_text(INIT, CcPfParametersSetDefaults)
  19. #pragma alloc_text(PAGE, CcPfParametersRead)
  20. #pragma alloc_text(PAGE, CcPfParametersSave)
  21. #pragma alloc_text(PAGE, CcPfParametersVerify)
  22. #pragma alloc_text(PAGE, CcPfParametersWatcher)
  23. #pragma alloc_text(PAGE, CcPfParametersSetChangedEvent)
  24. #pragma alloc_text(PAGE, CcPfGetParameter)
  25. #pragma alloc_text(PAGE, CcPfSetParameter)
  26. #pragma alloc_text(PAGE, CcPfDetermineEnablePrefetcher)
  27. #pragma alloc_text(PAGE, CcPfIsHostingApplication)
  28. #endif // ALLOC_PRAGMA
  29. //
  30. // Globals:
  31. //
  32. extern CCPF_PREFETCHER_GLOBALS CcPfGlobals;
  33. //
  34. // Constants:
  35. //
  36. //
  37. // The following are used as prefixs for the value names for registry
  38. // parameters that are per scenario type.
  39. //
  40. WCHAR *CcPfAppLaunchScenarioTypePrefix = L"AppLaunch";
  41. WCHAR *CcPfBootScenarioTypePrefix = L"Boot";
  42. //
  43. // Routines for prefetcher parameter handling.
  44. //
  45. NTSTATUS
  46. CcPfParametersInitialize (
  47. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  48. )
  49. /*++
  50. Routine Description:
  51. Initializes specified prefetcher parameters structure.
  52. Arguments:
  53. PrefetcherParameters - Pointer to structure to initialize.
  54. Return Value:
  55. Status.
  56. Environment:
  57. Kernel mode. IRQL == PASSIVE_LEVEL.
  58. Notes:
  59. The code & local constants for this function gets discarded after system boots.
  60. --*/
  61. {
  62. OBJECT_ATTRIBUTES ObjectAttributes;
  63. UNICODE_STRING KeyName;
  64. NTSTATUS Status;
  65. //
  66. // Zero out the structure. This initializes:
  67. // ParametersVersion
  68. //
  69. RtlZeroMemory(PrefetcherParameters, sizeof(*PrefetcherParameters));
  70. //
  71. // Initialize the lock protecting the parameters and parameters
  72. // version. Each time parameters are updated, the version is
  73. // bumped.
  74. //
  75. ExInitializeResourceLite(&PrefetcherParameters->ParametersLock);
  76. //
  77. // Initialize the workitem used for registry notifications on the
  78. // parameters key.
  79. //
  80. ExInitializeWorkItem(&PrefetcherParameters->RegistryWatchWorkItem,
  81. CcPfParametersWatcher,
  82. PrefetcherParameters);
  83. //
  84. // Set default parameters.
  85. //
  86. CcPfParametersSetDefaults(PrefetcherParameters);
  87. //
  88. // Create / Open the registry key that contains our parameters.
  89. //
  90. RtlInitUnicodeString(&KeyName, CCPF_PARAMETERS_KEY);
  91. InitializeObjectAttributes(&ObjectAttributes,
  92. &KeyName,
  93. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  94. NULL,
  95. NULL);
  96. Status = ZwCreateKey(&PrefetcherParameters->ParametersKey,
  97. KEY_ALL_ACCESS,
  98. &ObjectAttributes,
  99. 0,
  100. NULL,
  101. REG_OPTION_NON_VOLATILE,
  102. 0);
  103. if (NT_SUCCESS(Status)) {
  104. //
  105. // Update the default parameters with those in the registry.
  106. //
  107. Status = CcPfParametersRead(PrefetcherParameters);
  108. if (!NT_SUCCESS(Status)) {
  109. DBGPR((CCPFID,PFERR,"CCPF: Init-FailedReadParams=%x\n",Status));
  110. }
  111. //
  112. // Request notification when something changes in the
  113. // prefetcher parameters key.
  114. //
  115. Status = ZwNotifyChangeKey(PrefetcherParameters->ParametersKey,
  116. NULL,
  117. (PIO_APC_ROUTINE)&PrefetcherParameters->RegistryWatchWorkItem,
  118. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  119. &PrefetcherParameters->RegistryWatchIosb,
  120. REG_LEGAL_CHANGE_FILTER,
  121. FALSE,
  122. &PrefetcherParameters->RegistryWatchBuffer,
  123. sizeof(PrefetcherParameters->RegistryWatchBuffer),
  124. TRUE);
  125. if (!NT_SUCCESS(Status)) {
  126. //
  127. // Although we could not register a notification, this
  128. // is not a fatal error.
  129. //
  130. DBGPR((CCPFID,PFERR,"CCPF: Init-FailedSetParamNotify=%x\n",Status));
  131. }
  132. } else {
  133. DBGPR((CCPFID,PFERR,"CCPF: Init-FailedCreateParamKey=%x\n",Status));
  134. }
  135. return Status;
  136. }
  137. VOID
  138. CcPfParametersSetDefaults (
  139. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  140. )
  141. /*++
  142. Routine Description:
  143. Initializes specified parameters structure to default values.
  144. Arguments:
  145. Parameters - Pointer to structure to initialize.
  146. Return Value:
  147. None.
  148. Environment:
  149. Kernel mode. IRQL == PASSIVE_LEVEL.
  150. Notes:
  151. The code & local constants for this function gets discarded after system boots.
  152. --*/
  153. {
  154. PPF_SYSTEM_PREFETCH_PARAMETERS Parameters;
  155. PPF_TRACE_LIMITS TraceLimits;
  156. PF_SCENARIO_TYPE ScenarioType;
  157. //
  158. // Initialize locals.
  159. //
  160. Parameters = &PrefetcherParameters->Parameters;
  161. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  162. //
  163. // PfSvNotSpecified is currently treated as disabled.
  164. //
  165. Parameters->EnableStatus[ScenarioType] = PfSvNotSpecified;
  166. //
  167. // Trace limits are determined based on scenario type.
  168. //
  169. TraceLimits = &Parameters->TraceLimits[ScenarioType];
  170. switch(ScenarioType) {
  171. case PfApplicationLaunchScenarioType:
  172. TraceLimits->MaxNumPages = 4000;
  173. TraceLimits->MaxNumSections = 170;
  174. TraceLimits->TimerPeriod = (-1 * 1000 * 1000 * 10);
  175. PrefetcherParameters->ScenarioTypePrefixes[ScenarioType] =
  176. CcPfAppLaunchScenarioTypePrefix;
  177. break;
  178. case PfSystemBootScenarioType:
  179. TraceLimits->MaxNumPages = 128000;
  180. TraceLimits->MaxNumSections = 4080;
  181. TraceLimits->TimerPeriod = (-1 * 12000 * 1000 * 10);
  182. PrefetcherParameters->ScenarioTypePrefixes[ScenarioType] =
  183. CcPfBootScenarioTypePrefix;
  184. break;
  185. default:
  186. //
  187. // We should be handling all scenario types above.
  188. //
  189. CCPF_ASSERT(FALSE);
  190. TraceLimits->MaxNumPages = PF_MAXIMUM_PAGES;
  191. TraceLimits->MaxNumSections = PF_MAXIMUM_SECTIONS;
  192. TraceLimits->TimerPeriod = (-1 * 1000 * 1000 * 10);
  193. PrefetcherParameters->ScenarioTypePrefixes[ScenarioType] = L"XXX";
  194. }
  195. }
  196. //
  197. // These limits ensure that we don't monopolize system resources
  198. // for prefetching.
  199. //
  200. Parameters->MaxNumActiveTraces = 8;
  201. Parameters->MaxNumSavedTraces = 8;
  202. //
  203. // This is the default directory under SystemRoot where we
  204. // find prefetch instructions for scenarios. During upgrades
  205. // we remove the contents of this directory, so "Prefetch" is
  206. // hardcoded in txtsetup.inx.
  207. //
  208. wcsncpy(Parameters->RootDirPath,
  209. L"Prefetch",
  210. PF_MAX_PREFETCH_ROOT_PATH);
  211. Parameters->RootDirPath[PF_MAX_PREFETCH_ROOT_PATH - 1] = 0;
  212. //
  213. // This is the default list of known hosting applications.
  214. //
  215. wcsncpy(Parameters->HostingApplicationList,
  216. L"DLLHOST.EXE,MMC.EXE,RUNDLL32.EXE",
  217. PF_HOSTING_APP_LIST_MAX_CHARS);
  218. Parameters->HostingApplicationList[PF_HOSTING_APP_LIST_MAX_CHARS - 1] = 0;
  219. //
  220. // Make sure the default parameters make sense.
  221. //
  222. CCPF_ASSERT(NT_SUCCESS(CcPfParametersVerify(Parameters)));
  223. }
  224. NTSTATUS
  225. CcPfParametersRead (
  226. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  227. )
  228. /*++
  229. Routine Description:
  230. This routine updates the parameters structure with the
  231. parameters in the registry.
  232. Keep the value names that are used in sync with the function to
  233. save the parameters.
  234. Arguments:
  235. PrefetcherParameters - Pointer to parameters.
  236. Return Value:
  237. Status.
  238. Environment:
  239. Kernel mode. IRQL == PASSIVE_LEVEL.
  240. --*/
  241. {
  242. NTSTATUS Status;
  243. PF_SYSTEM_PREFETCH_PARAMETERS Parameters;
  244. PPF_TRACE_LIMITS TraceLimits;
  245. PF_SCENARIO_TYPE ScenarioType;
  246. WCHAR ValueName[CCPF_MAX_PARAMETER_NAME_LENGTH];
  247. WCHAR *ValueNamePrefix;
  248. HANDLE ParametersKey;
  249. BOOLEAN EnableStatusSpecified;
  250. ULONG EnablePrefetcher;
  251. BOOLEAN AcquiredParametersLock;
  252. ULONG Length;
  253. LONG CurrentVersion;
  254. ULONG RetryCount;
  255. PKTHREAD CurrentThread;
  256. //
  257. // Initialize locals.
  258. //
  259. CurrentThread = KeGetCurrentThread ();
  260. AcquiredParametersLock = FALSE;
  261. RetryCount = 0;
  262. DBGPR((CCPFID,PFTRC,"CCPF: ParametersRead()\n"));
  263. //
  264. // If we could not initialize the parameters key, we would fail
  265. // all the following ops miserably.
  266. //
  267. if (!PrefetcherParameters->ParametersKey) {
  268. Status = STATUS_REINITIALIZATION_NEEDED;
  269. goto cleanup;
  270. }
  271. do {
  272. //
  273. // Get the parameters lock shared.
  274. //
  275. KeEnterCriticalRegionThread(CurrentThread);
  276. ExAcquireResourceSharedLite(&PrefetcherParameters->ParametersLock, TRUE);
  277. AcquiredParametersLock = TRUE;
  278. ParametersKey = PrefetcherParameters->ParametersKey;
  279. //
  280. // Save current version of parameters. Each time parameters gets
  281. // updated, the version is bumped.
  282. //
  283. CurrentVersion = PrefetcherParameters->ParametersVersion;
  284. //
  285. // Copy over existing parameters to the parameters structure we
  286. // are building. This way, if we cannot get a value from the
  287. // registry we'll keep the value we already have.
  288. //
  289. Parameters = PrefetcherParameters->Parameters;
  290. //
  291. // Read the prefetcher enable value. Depending on whether it is
  292. // specified and if so its value we will set enable status for
  293. // prefetch scenario types.
  294. //
  295. Length = sizeof(EnablePrefetcher);
  296. Status = CcPfGetParameter(ParametersKey,
  297. L"EnablePrefetcher",
  298. REG_DWORD,
  299. &EnablePrefetcher,
  300. &Length);
  301. if (!NT_SUCCESS(Status)) {
  302. //
  303. // Enable status is not specified or we cannot access it.
  304. //
  305. EnableStatusSpecified = FALSE;
  306. } else {
  307. EnableStatusSpecified = TRUE;
  308. }
  309. //
  310. // Get per scenario parameters.
  311. //
  312. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  313. ValueNamePrefix = PrefetcherParameters->ScenarioTypePrefixes[ScenarioType];
  314. //
  315. // Determine enable status. If EnableStatusSpecified, whether
  316. // prefeching for this scenario type is on or off is
  317. // determined by the ScenarioType'th bit in EnablePrefetcher.
  318. //
  319. if (EnableStatusSpecified) {
  320. if (EnablePrefetcher & (1 << ScenarioType)) {
  321. Parameters.EnableStatus[ScenarioType] = PfSvEnabled;
  322. } else {
  323. Parameters.EnableStatus[ScenarioType] = PfSvDisabled;
  324. }
  325. } else {
  326. Parameters.EnableStatus[ScenarioType] = PfSvNotSpecified;
  327. }
  328. //
  329. // Update trace limits for this scenario type. Ignore return
  330. // value from GetParameter since the value may not be
  331. // specified in the registry. If so the current value is kept
  332. // intact.
  333. //
  334. TraceLimits = &Parameters.TraceLimits[ScenarioType];
  335. wcscpy(ValueName, ValueNamePrefix);
  336. wcscat(ValueName, L"MaxNumPages");
  337. Length = sizeof(TraceLimits->MaxNumPages);
  338. CcPfGetParameter(ParametersKey,
  339. ValueName,
  340. REG_DWORD,
  341. &TraceLimits->MaxNumPages,
  342. &Length);
  343. wcscpy(ValueName, ValueNamePrefix);
  344. wcscat(ValueName, L"MaxNumSections");
  345. Length = sizeof(TraceLimits->MaxNumSections);
  346. CcPfGetParameter(ParametersKey,
  347. ValueName,
  348. REG_DWORD,
  349. &TraceLimits->MaxNumSections,
  350. &Length);
  351. wcscpy(ValueName, ValueNamePrefix);
  352. wcscat(ValueName, L"TimerPeriod");
  353. Length = sizeof(TraceLimits->TimerPeriod);
  354. CcPfGetParameter(ParametersKey,
  355. ValueName,
  356. REG_BINARY,
  357. &TraceLimits->TimerPeriod,
  358. &Length);
  359. }
  360. //
  361. // Update maximum number of active traces.
  362. //
  363. Length = sizeof(Parameters.MaxNumActiveTraces);
  364. CcPfGetParameter(ParametersKey,
  365. L"MaxNumActiveTraces",
  366. REG_DWORD,
  367. &Parameters.MaxNumActiveTraces,
  368. &Length);
  369. //
  370. // Update maximum number of saved traces.
  371. //
  372. Length = sizeof(Parameters.MaxNumSavedTraces);
  373. CcPfGetParameter(ParametersKey,
  374. L"MaxNumSavedTraces",
  375. REG_DWORD,
  376. &Parameters.MaxNumSavedTraces,
  377. &Length);
  378. //
  379. // Update the root directory path.
  380. //
  381. Length = sizeof(Parameters.RootDirPath);
  382. CcPfGetParameter(ParametersKey,
  383. L"RootDirPath",
  384. REG_SZ,
  385. Parameters.RootDirPath,
  386. &Length);
  387. //
  388. // Update list of known hosting applications.
  389. //
  390. Length = sizeof(Parameters.HostingApplicationList);
  391. CcPfGetParameter(ParametersKey,
  392. L"HostingAppList",
  393. REG_SZ,
  394. Parameters.HostingApplicationList,
  395. &Length);
  396. Parameters.HostingApplicationList[PF_HOSTING_APP_LIST_MAX_CHARS - 1] = 0;
  397. _wcsupr(Parameters.HostingApplicationList);
  398. //
  399. // Verify the parameters updated from the registry.
  400. //
  401. Status = CcPfParametersVerify(&Parameters);
  402. if (!NT_SUCCESS(Status)) {
  403. goto cleanup;
  404. }
  405. //
  406. // Release the shared lock and acquire it exclusive.
  407. //
  408. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  409. KeLeaveCriticalRegionThread(CurrentThread);
  410. KeEnterCriticalRegionThread(CurrentThread);
  411. ExAcquireResourceExclusiveLite(&PrefetcherParameters->ParametersLock, TRUE);
  412. //
  413. // Check if somebody already updated the parameters before us.
  414. //
  415. if (CurrentVersion != PrefetcherParameters->ParametersVersion) {
  416. //
  417. // Bummer. Somebody updated parameters when we released
  418. // our shared lock to acquire it exclusive. We have to try
  419. // again. The default values we used for parameters that
  420. // were not in the registry may have been changed.
  421. //
  422. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  423. KeLeaveCriticalRegionThread(CurrentThread);
  424. AcquiredParametersLock = FALSE;
  425. RetryCount++;
  426. continue;
  427. }
  428. //
  429. // We are updating the parameters, bump the version.
  430. //
  431. PrefetcherParameters->ParametersVersion++;
  432. PrefetcherParameters->Parameters = Parameters;
  433. //
  434. // Release the exclusive lock and break out.
  435. //
  436. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  437. KeLeaveCriticalRegionThread(CurrentThread);
  438. AcquiredParametersLock = FALSE;
  439. break;
  440. } while (RetryCount < 10);
  441. //
  442. // See if we looped too many times and could not achive updating
  443. // the parameters.
  444. //
  445. if (RetryCount >= 10) {
  446. Status = STATUS_RETRY;
  447. goto cleanup;
  448. }
  449. //
  450. // Otherwise we were successful.
  451. //
  452. Status = STATUS_SUCCESS;
  453. cleanup:
  454. if (AcquiredParametersLock) {
  455. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  456. KeLeaveCriticalRegionThread(CurrentThread);
  457. }
  458. DBGPR((CCPFID,PFTRC,"CCPF: ParametersRead()=%x\n", Status));
  459. return Status;
  460. }
  461. NTSTATUS
  462. CcPfParametersSave (
  463. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  464. )
  465. /*++
  466. Routine Description:
  467. This routine updates the registry with the specified prefetch
  468. parameters.
  469. Arguments:
  470. PrefetcherParameters - Pointer to parameters structure.
  471. Return Value:
  472. Status.
  473. Environment:
  474. Kernel mode. IRQL == PASSIVE_LEVEL.
  475. --*/
  476. {
  477. NTSTATUS Status;
  478. PPF_TRACE_LIMITS TraceLimits;
  479. PF_SCENARIO_TYPE ScenarioType;
  480. WCHAR ValueName[CCPF_MAX_PARAMETER_NAME_LENGTH];
  481. WCHAR *ValueNamePrefix;
  482. HANDLE ParametersKey;
  483. BOOLEAN EnableStatusSpecified;
  484. ULONG EnablePrefetcher;
  485. BOOLEAN AcquiredParametersLock;
  486. ULONG Length;
  487. PPF_SYSTEM_PREFETCH_PARAMETERS Parameters;
  488. PKTHREAD CurrentThread;
  489. //
  490. // Initialize locals.
  491. //
  492. CurrentThread = KeGetCurrentThread ();
  493. ParametersKey = PrefetcherParameters->ParametersKey;
  494. Parameters = &PrefetcherParameters->Parameters;
  495. AcquiredParametersLock = FALSE;
  496. DBGPR((CCPFID,PFTRC,"CCPF: ParametersSave()\n"));
  497. //
  498. // If we could not initialize the parameters key, we would fail
  499. // all the following ops miserably.
  500. //
  501. if (!PrefetcherParameters->ParametersKey) {
  502. Status = STATUS_REINITIALIZATION_NEEDED;
  503. goto cleanup;
  504. }
  505. //
  506. // Get the parameters lock shared.
  507. //
  508. KeEnterCriticalRegionThread(CurrentThread);
  509. ExAcquireResourceSharedLite(&PrefetcherParameters->ParametersLock, TRUE);
  510. AcquiredParametersLock = TRUE;
  511. //
  512. // Build up the prefetcher enable value.
  513. //
  514. EnableStatusSpecified = FALSE;
  515. EnablePrefetcher = 0;
  516. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  517. //
  518. // By default prefetching for all scenario types will be
  519. // disabled, except it is explicitly enabled.
  520. //
  521. if (Parameters->EnableStatus[ScenarioType] == PfSvEnabled) {
  522. EnablePrefetcher |= (1 << ScenarioType);
  523. }
  524. //
  525. // Even if enable status for one scenario type is specified,
  526. // we have to save the enable prefetcher key.
  527. //
  528. if (Parameters->EnableStatus[ScenarioType] != PfSvNotSpecified) {
  529. EnableStatusSpecified = TRUE;
  530. }
  531. }
  532. if (EnableStatusSpecified) {
  533. //
  534. // Save the prefetcher enable key.
  535. //
  536. Length = sizeof(EnablePrefetcher);
  537. Status = CcPfSetParameter(ParametersKey,
  538. L"EnablePrefetcher",
  539. REG_DWORD,
  540. &EnablePrefetcher,
  541. Length);
  542. if (!NT_SUCCESS(Status)) {
  543. goto cleanup;
  544. }
  545. }
  546. //
  547. // Save per scenario parameters.
  548. //
  549. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  550. ValueNamePrefix = PrefetcherParameters->ScenarioTypePrefixes[ScenarioType];
  551. //
  552. // Update trace limits for this scenario type.
  553. //
  554. TraceLimits = &Parameters->TraceLimits[ScenarioType];
  555. wcscpy(ValueName, ValueNamePrefix);
  556. wcscat(ValueName, L"MaxNumPages");
  557. Length = sizeof(TraceLimits->MaxNumPages);
  558. Status = CcPfSetParameter(ParametersKey,
  559. ValueName,
  560. REG_DWORD,
  561. &TraceLimits->MaxNumPages,
  562. Length);
  563. if (!NT_SUCCESS(Status)) {
  564. goto cleanup;
  565. }
  566. wcscpy(ValueName, ValueNamePrefix);
  567. wcscat(ValueName, L"MaxNumSections");
  568. Length = sizeof(TraceLimits->MaxNumSections);
  569. Status = CcPfSetParameter(ParametersKey,
  570. ValueName,
  571. REG_DWORD,
  572. &TraceLimits->MaxNumSections,
  573. Length);
  574. if (!NT_SUCCESS(Status)) {
  575. goto cleanup;
  576. }
  577. wcscpy(ValueName, ValueNamePrefix);
  578. wcscat(ValueName, L"TimerPeriod");
  579. Length = sizeof(TraceLimits->TimerPeriod);
  580. Status = CcPfSetParameter(ParametersKey,
  581. ValueName,
  582. REG_BINARY,
  583. &TraceLimits->TimerPeriod,
  584. Length);
  585. if (!NT_SUCCESS(Status)) {
  586. goto cleanup;
  587. }
  588. }
  589. //
  590. // Update maximum number of active traces.
  591. //
  592. Length = sizeof(Parameters->MaxNumActiveTraces);
  593. Status = CcPfSetParameter(ParametersKey,
  594. L"MaxNumActiveTraces",
  595. REG_DWORD,
  596. &Parameters->MaxNumActiveTraces,
  597. Length);
  598. if (!NT_SUCCESS(Status)) {
  599. goto cleanup;
  600. }
  601. //
  602. // Update maximum number of saved traces.
  603. //
  604. Length = sizeof(Parameters->MaxNumSavedTraces);
  605. Status = CcPfSetParameter(ParametersKey,
  606. L"MaxNumSavedTraces",
  607. REG_DWORD,
  608. &Parameters->MaxNumSavedTraces,
  609. Length);
  610. if (!NT_SUCCESS(Status)) {
  611. goto cleanup;
  612. }
  613. //
  614. // Update the root directory path.
  615. //
  616. Length = (wcslen(Parameters->RootDirPath) + 1) * sizeof(WCHAR);
  617. Status = CcPfSetParameter(ParametersKey,
  618. L"RootDirPath",
  619. REG_SZ,
  620. Parameters->RootDirPath,
  621. Length);
  622. if (!NT_SUCCESS(Status)) {
  623. goto cleanup;
  624. }
  625. //
  626. // Update the hosting application list path.
  627. //
  628. Length = (wcslen(Parameters->HostingApplicationList) + 1) * sizeof(WCHAR);
  629. Status = CcPfSetParameter(ParametersKey,
  630. L"HostingAppList",
  631. REG_SZ,
  632. Parameters->HostingApplicationList,
  633. Length);
  634. if (!NT_SUCCESS(Status)) {
  635. goto cleanup;
  636. }
  637. Status = STATUS_SUCCESS;
  638. cleanup:
  639. if (AcquiredParametersLock) {
  640. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  641. KeLeaveCriticalRegionThread(CurrentThread);
  642. }
  643. DBGPR((CCPFID,PFTRC,"CCPF: ParametersSave()=%x\n", Status));
  644. return Status;
  645. }
  646. NTSTATUS
  647. CcPfParametersVerify (
  648. PPF_SYSTEM_PREFETCH_PARAMETERS Parameters
  649. )
  650. /*++
  651. Routine Description:
  652. This routine verifies that the specified parameters structure is
  653. valid and within sanity limits.
  654. Arguments:
  655. Parameters - Pointer to parameters structure.
  656. Return Value:
  657. Status.
  658. Environment:
  659. Kernel mode. IRQL == PASSIVE_LEVEL.
  660. --*/
  661. {
  662. NTSTATUS Status;
  663. ULONG FailedCheckId;
  664. ULONG CharIdx;
  665. BOOLEAN FoundNUL;
  666. PF_SCENARIO_TYPE ScenarioType;
  667. PPF_TRACE_LIMITS TraceLimits;
  668. //
  669. // Initialize locals.
  670. //
  671. Status = STATUS_INVALID_PARAMETER;
  672. FailedCheckId = 0;
  673. DBGPR((CCPFID,PFTRC,"CCPF: ParametersVerify\n"));
  674. //
  675. // Make sure RootDirPath is NUL terminated.
  676. //
  677. FoundNUL = FALSE;
  678. for (CharIdx = 0; CharIdx < PF_MAX_PREFETCH_ROOT_PATH; CharIdx++) {
  679. if (Parameters->RootDirPath[CharIdx] == 0) {
  680. FoundNUL = TRUE;
  681. break;
  682. }
  683. }
  684. if (FoundNUL == FALSE) {
  685. FailedCheckId = 10;
  686. goto cleanup;
  687. }
  688. //
  689. // Make sure HostingApplicationList is NUL terminated.
  690. //
  691. FoundNUL = FALSE;
  692. for (CharIdx = 0; CharIdx < PF_HOSTING_APP_LIST_MAX_CHARS; CharIdx++) {
  693. if (Parameters->HostingApplicationList[CharIdx] == 0) {
  694. FoundNUL = TRUE;
  695. break;
  696. }
  697. }
  698. if (FoundNUL == FALSE) {
  699. FailedCheckId = 15;
  700. goto cleanup;
  701. }
  702. //
  703. // Make sure all per scenario type parameters types are within
  704. // sanity limits.
  705. //
  706. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  707. if (Parameters->EnableStatus[ScenarioType] >= PfSvMaxEnableStatus) {
  708. FailedCheckId = 20;
  709. goto cleanup;
  710. }
  711. //
  712. // Check trace limits.
  713. //
  714. TraceLimits = &Parameters->TraceLimits[ScenarioType];
  715. if (TraceLimits->MaxNumPages > PF_MAXIMUM_PAGES) {
  716. FailedCheckId = 30;
  717. goto cleanup;
  718. }
  719. if (TraceLimits->MaxNumSections > PF_MAXIMUM_SECTIONS) {
  720. FailedCheckId = 40;
  721. goto cleanup;
  722. }
  723. if ((TraceLimits->TimerPeriod < PF_MAXIMUM_TIMER_PERIOD) ||
  724. (TraceLimits->TimerPeriod >= 0)) {
  725. FailedCheckId = 50;
  726. goto cleanup;
  727. }
  728. }
  729. //
  730. // Check limits on active/saved traces.
  731. //
  732. if (Parameters->MaxNumActiveTraces > PF_MAXIMUM_ACTIVE_TRACES) {
  733. FailedCheckId = 60;
  734. goto cleanup;
  735. }
  736. if (Parameters->MaxNumSavedTraces > PF_MAXIMUM_SAVED_TRACES) {
  737. FailedCheckId = 70;
  738. goto cleanup;
  739. }
  740. //
  741. // We passed all the checks.
  742. //
  743. Status = STATUS_SUCCESS;
  744. cleanup:
  745. DBGPR((CCPFID,PFTRC,"CCPF: ParametersVerify()=%x,%d\n", Status, FailedCheckId));
  746. return Status;
  747. }
  748. VOID
  749. CcPfParametersWatcher(
  750. IN PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  751. )
  752. /*++
  753. Routine Description:
  754. This routine gets called when our parameters in the registry change.
  755. Arguments:
  756. PrefetcherParameters - Pointer to parameters structure.
  757. Return Value:
  758. None.
  759. Environment:
  760. Kernel mode. IRQL == PASSIVE_LEVEL.
  761. --*/
  762. {
  763. NTSTATUS Status;
  764. UNICODE_STRING KeyName;
  765. OBJECT_ATTRIBUTES ObjectAttributes;
  766. HANDLE ParametersKey;
  767. PKTHREAD CurrentThread;
  768. HANDLE TempHandle;
  769. DBGPR((CCPFID,PFTRC,"CCPF: ParametersWatcher()\n"));
  770. //
  771. // In order to have setup a registry watch, we should have
  772. // initialized the parameters key successfully.
  773. //
  774. CCPF_ASSERT(PrefetcherParameters->ParametersKey);
  775. //
  776. // Our change notify triggered. Request further notification. But
  777. // first wait until we can get the parameters lock exclusive, so
  778. // while we are saving parameters to the registry we don't kick
  779. // off a notification for each key.
  780. //
  781. CurrentThread = KeGetCurrentThread ();
  782. KeEnterCriticalRegionThread(CurrentThread);
  783. ExAcquireResourceExclusiveLite(&PrefetcherParameters->ParametersLock, TRUE);
  784. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  785. KeLeaveCriticalRegionThread(CurrentThread);
  786. Status = ZwNotifyChangeKey(PrefetcherParameters->ParametersKey,
  787. NULL,
  788. (PIO_APC_ROUTINE)&PrefetcherParameters->RegistryWatchWorkItem,
  789. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  790. &PrefetcherParameters->RegistryWatchIosb,
  791. REG_LEGAL_CHANGE_FILTER,
  792. FALSE,
  793. &PrefetcherParameters->RegistryWatchBuffer,
  794. sizeof(PrefetcherParameters->RegistryWatchBuffer),
  795. TRUE);
  796. if (!NT_SUCCESS(Status)) {
  797. //
  798. // Somebody may have deleted the key. We have to recreate it then.
  799. //
  800. if (Status == STATUS_KEY_DELETED) {
  801. RtlInitUnicodeString(&KeyName, CCPF_PARAMETERS_KEY);
  802. InitializeObjectAttributes(&ObjectAttributes,
  803. &KeyName,
  804. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  805. NULL,
  806. NULL);
  807. Status = ZwCreateKey(&ParametersKey,
  808. KEY_ALL_ACCESS,
  809. &ObjectAttributes,
  810. 0,
  811. NULL,
  812. REG_OPTION_NON_VOLATILE,
  813. 0);
  814. if (!NT_SUCCESS(Status)) {
  815. DBGPR((CCPFID,PFERR,"CCPF: ParametersWatcher-FailedRecreate=%x\n",Status));
  816. return;
  817. }
  818. //
  819. // Update global key handle.
  820. //
  821. KeEnterCriticalRegionThread(CurrentThread);
  822. ExAcquireResourceExclusiveLite(&PrefetcherParameters->ParametersLock, TRUE);
  823. TempHandle = PrefetcherParameters->ParametersKey;
  824. PrefetcherParameters->ParametersKey = ParametersKey;
  825. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  826. KeLeaveCriticalRegionThread(CurrentThread);
  827. ZwClose(TempHandle);
  828. //
  829. // Retry setting a notification again.
  830. //
  831. Status = ZwNotifyChangeKey(PrefetcherParameters->ParametersKey,
  832. NULL,
  833. (PIO_APC_ROUTINE)&PrefetcherParameters->RegistryWatchWorkItem,
  834. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  835. &PrefetcherParameters->RegistryWatchIosb,
  836. REG_LEGAL_CHANGE_FILTER,
  837. FALSE,
  838. &PrefetcherParameters->RegistryWatchBuffer,
  839. sizeof(PrefetcherParameters->RegistryWatchBuffer),
  840. TRUE);
  841. if (!NT_SUCCESS(Status)) {
  842. DBGPR((CCPFID,PFERR,"CCPF: ParametersWatcher-FailedReSetNotify=%x\n",Status));
  843. return;
  844. }
  845. } else {
  846. DBGPR((CCPFID,PFERR,"CCPF: ParametersWatcher-FailedSetNotify=%x\n",Status));
  847. return;
  848. }
  849. }
  850. //
  851. // Update the global parameters.
  852. //
  853. Status = CcPfParametersRead(PrefetcherParameters);
  854. if (NT_SUCCESS(Status)) {
  855. //
  856. // Determine if prefetching is enabled.
  857. //
  858. CcPfDetermineEnablePrefetcher();
  859. //
  860. // Set the event so the service queries for the latest parameters.
  861. //
  862. CcPfParametersSetChangedEvent(PrefetcherParameters);
  863. }
  864. return;
  865. }
  866. NTSTATUS
  867. CcPfParametersSetChangedEvent(
  868. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  869. )
  870. /*++
  871. Routine Description:
  872. This routine tries to open and set the event that tells the
  873. service system prefetch parameters have changed.
  874. Arguments:
  875. None.
  876. Return Value:
  877. Status.
  878. Environment:
  879. Kernel mode. IRQL == PASSIVE_LEVEL.
  880. --*/
  881. {
  882. NTSTATUS Status;
  883. UNICODE_STRING EventName;
  884. OBJECT_ATTRIBUTES EventObjAttr;
  885. HANDLE EventHandle;
  886. PKTHREAD CurrentThread;
  887. DBGPR((CCPFID,PFTRC,"CCPF: ParametersSetChangedEvent()\n"));
  888. //
  889. // If we have already opened the event, just signal it.
  890. //
  891. if (PrefetcherParameters->ParametersChangedEvent) {
  892. ZwSetEvent(PrefetcherParameters->ParametersChangedEvent, NULL);
  893. Status = STATUS_SUCCESS;
  894. } else {
  895. //
  896. // Try to open the event. We don't open this at initialization
  897. // because our service may not have started to create this
  898. // event yet. If csrss.exe has not initialized, we may not
  899. // even have the BaseNamedObjects object directory created, in
  900. // which Win32 events reside.
  901. //
  902. RtlInitUnicodeString(&EventName, PF_PARAMETERS_CHANGED_EVENT_NAME);
  903. InitializeObjectAttributes(&EventObjAttr,
  904. &EventName,
  905. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  906. NULL,
  907. NULL);
  908. Status = ZwOpenEvent(&EventHandle,
  909. EVENT_ALL_ACCESS,
  910. &EventObjAttr);
  911. if (NT_SUCCESS(Status)) {
  912. //
  913. // Acquire the lock and set the global handle.
  914. //
  915. CurrentThread = KeGetCurrentThread ();
  916. KeEnterCriticalRegionThread(CurrentThread);
  917. ExAcquireResourceExclusiveLite(&PrefetcherParameters->ParametersLock, TRUE);
  918. if (!PrefetcherParameters->ParametersChangedEvent) {
  919. //
  920. // Set the global handle.
  921. //
  922. PrefetcherParameters->ParametersChangedEvent = EventHandle;
  923. CCPF_ASSERT(EventHandle);
  924. EventHandle = NULL;
  925. }
  926. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  927. KeLeaveCriticalRegionThread(CurrentThread);
  928. if (EventHandle != NULL) {
  929. //
  930. // Somebody already initialized the global handle
  931. // before us. Close our handle and use the one they
  932. // initialized.
  933. //
  934. ZwClose(EventHandle);
  935. }
  936. //
  937. // We have an event now. Signal it.
  938. //
  939. ZwSetEvent(PrefetcherParameters->ParametersChangedEvent, NULL);
  940. }
  941. }
  942. DBGPR((CCPFID,PFTRC,"CCPF: ParametersSetChangedEvent()=%x\n", Status));
  943. return Status;
  944. }
  945. NTSTATUS
  946. CcPfGetParameter (
  947. HANDLE ParametersKey,
  948. WCHAR *ValueNameBuffer,
  949. ULONG ValueType,
  950. PVOID Value,
  951. ULONG *ValueSize
  952. )
  953. /*++
  954. Routine Description:
  955. This routine queries a value under the specified registry into the
  956. specified buffer. Contents of Value and ValueSize are not changed
  957. if returning failure.
  958. Arguments:
  959. ParametersKey - Handle to key to query value under.
  960. ValueNameBuffer - Name of the value.
  961. ValueType - What the type of that value should be. (e.g. REG_DWORD).
  962. Value - Queried value data gets put here.
  963. ValueSize - Size of Value buffer in bytes. On successful return
  964. this is set to number of bytes copied into Value.
  965. Return Value:
  966. Status.
  967. Environment:
  968. Kernel mode. IRQL == PASSIVE_LEVEL.
  969. --*/
  970. {
  971. UNICODE_STRING ValueName;
  972. CHAR Buffer[CCPF_MAX_PARAMETER_VALUE_BUFFER];
  973. PKEY_VALUE_PARTIAL_INFORMATION ValueBuffer;
  974. ULONG Length;
  975. NTSTATUS Status;
  976. //
  977. // Initialize locals.
  978. //
  979. ValueBuffer = (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
  980. Length = CCPF_MAX_PARAMETER_VALUE_BUFFER;
  981. RtlInitUnicodeString(&ValueName, ValueNameBuffer);
  982. DBGPR((CCPFID,PFTRC,"CCPF: GetParameter(%ws,%x)\n", ValueNameBuffer, ValueType));
  983. //
  984. // Query value.
  985. //
  986. Status = ZwQueryValueKey(ParametersKey,
  987. &ValueName,
  988. KeyValuePartialInformation,
  989. ValueBuffer,
  990. Length,
  991. &Length);
  992. if (!NT_SUCCESS(Status)) {
  993. goto cleanup;
  994. }
  995. //
  996. // Make sure ZwQueryValue returns valid information.
  997. //
  998. if (Length < sizeof(KEY_VALUE_PARTIAL_INFORMATION)) {
  999. CCPF_ASSERT(Length >= sizeof(KEY_VALUE_PARTIAL_INFORMATION));
  1000. Status = STATUS_UNSUCCESSFUL;
  1001. goto cleanup;
  1002. }
  1003. //
  1004. // Check value type.
  1005. //
  1006. if (ValueBuffer->Type != ValueType) {
  1007. Status = STATUS_OBJECT_TYPE_MISMATCH;
  1008. goto cleanup;
  1009. }
  1010. //
  1011. // Check if data will fit into the buffer caller passed in.
  1012. //
  1013. if (ValueBuffer->DataLength > *ValueSize) {
  1014. Status = STATUS_BUFFER_TOO_SMALL;
  1015. goto cleanup;
  1016. }
  1017. //
  1018. // Copy data into user's buffer.
  1019. //
  1020. RtlCopyMemory(Value, ValueBuffer->Data, ValueBuffer->DataLength);
  1021. //
  1022. // Set copied number of bytes.
  1023. //
  1024. *ValueSize = ValueBuffer->DataLength;
  1025. Status = STATUS_SUCCESS;
  1026. cleanup:
  1027. DBGPR((CCPFID,PFTRC,"CCPF: GetParameter(%ws)=%x\n", ValueNameBuffer, Status));
  1028. return Status;
  1029. }
  1030. NTSTATUS
  1031. CcPfSetParameter (
  1032. HANDLE ParametersKey,
  1033. WCHAR *ValueNameBuffer,
  1034. ULONG ValueType,
  1035. PVOID Value,
  1036. ULONG ValueSize
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. This routine sets a parameter under the specified registry.
  1041. Arguments:
  1042. ParametersKey - Handle to key to query value under.
  1043. ValueNameBuffer - Name of the value.
  1044. ValueType - What the type of that value should be. (e.g. REG_DWORD).
  1045. Value - Data to save.
  1046. ValueSize - Size of Value buffer in bytes.
  1047. Return Value:
  1048. Status.
  1049. Environment:
  1050. Kernel mode. IRQL == PASSIVE_LEVEL.
  1051. --*/
  1052. {
  1053. UNICODE_STRING ValueName;
  1054. NTSTATUS Status;
  1055. //
  1056. // Initialize locals.
  1057. //
  1058. RtlInitUnicodeString(&ValueName, ValueNameBuffer);
  1059. DBGPR((CCPFID,PFTRC,"CCPF: SetParameter(%ws,%x)\n", ValueNameBuffer, ValueType));
  1060. //
  1061. // Save the value.
  1062. //
  1063. Status = ZwSetValueKey(ParametersKey,
  1064. &ValueName,
  1065. 0,
  1066. ValueType,
  1067. Value,
  1068. ValueSize);
  1069. //
  1070. // Return the status.
  1071. //
  1072. DBGPR((CCPFID,PFTRC,"CCPF: SetParameter(%ws)=%x\n", ValueNameBuffer, Status));
  1073. return Status;
  1074. }
  1075. LOGICAL
  1076. CcPfDetermineEnablePrefetcher(
  1077. VOID
  1078. )
  1079. /*++
  1080. Routine Description:
  1081. This routine sets the global CcPfEnablePrefetcher based on the
  1082. EnableStatus'es for all scenario types in global parameters as
  1083. well as other factors, such as whether we have booted safe mode.
  1084. Note: Acquires Parameters lock exclusive.
  1085. Arguments:
  1086. None.
  1087. Return Value:
  1088. New value of CcPfEnablePrefetcher.
  1089. Environment:
  1090. Kernel mode. IRQL == PASSIVE_LEVEL.
  1091. --*/
  1092. {
  1093. PF_SCENARIO_TYPE ScenarioType;
  1094. LOGICAL EnablePrefetcher;
  1095. PKTHREAD CurrentThread;
  1096. BOOLEAN IgnoreBootScenarioType;
  1097. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters;
  1098. extern PF_BOOT_PHASE_ID CcPfBootPhase;
  1099. //
  1100. // Initialize locals.
  1101. //
  1102. EnablePrefetcher = FALSE;
  1103. PrefetcherParameters = &CcPfGlobals.Parameters;
  1104. CurrentThread = KeGetCurrentThread ();
  1105. //
  1106. // Ignore whether prefetching is enabled for boot, if we've
  1107. // already past the point in boot where this matters.
  1108. //
  1109. IgnoreBootScenarioType = (CcPfBootPhase >= PfSessionManagerInitPhase) ? TRUE : FALSE;
  1110. KeEnterCriticalRegionThread(CurrentThread);
  1111. ExAcquireResourceExclusiveLite(&PrefetcherParameters->ParametersLock, TRUE);
  1112. //
  1113. // If we have booted to safe mode, the prefetcher will be disabled.
  1114. //
  1115. if (InitSafeBootMode) {
  1116. EnablePrefetcher = FALSE;
  1117. } else {
  1118. //
  1119. // By default prefetching is disabled. If prefetching is
  1120. // enabled for any scenario type, then the prefetcher is
  1121. // enabled.
  1122. //
  1123. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  1124. //
  1125. // Skip enable status for the boot scenario if requested.
  1126. //
  1127. if (IgnoreBootScenarioType) {
  1128. if (ScenarioType == PfSystemBootScenarioType) {
  1129. continue;
  1130. }
  1131. }
  1132. if (PrefetcherParameters->Parameters.EnableStatus[ScenarioType] == PfSvEnabled) {
  1133. EnablePrefetcher = TRUE;
  1134. break;
  1135. }
  1136. }
  1137. }
  1138. //
  1139. // Update global enable status.
  1140. //
  1141. CcPfEnablePrefetcher = EnablePrefetcher;
  1142. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  1143. KeLeaveCriticalRegionThread(CurrentThread);
  1144. return CcPfEnablePrefetcher;
  1145. }
  1146. BOOLEAN
  1147. CcPfIsHostingApplication(
  1148. IN PWCHAR ExecutableName
  1149. )
  1150. /*++
  1151. Routine Description:
  1152. This routine determines whether the specified executable is in the
  1153. list of known hosting applications, e.g. rundll32, dllhost etc.
  1154. Arguments:
  1155. ExecutableName - NUL terminated UPCASED executable name, e.g. "MMC.EXE"
  1156. Return Value:
  1157. TRUE - Executable is for a known hosting application.
  1158. FALSE - It is not.
  1159. Environment:
  1160. Kernel mode. IRQL == PASSIVE_LEVEL.
  1161. --*/
  1162. {
  1163. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters;
  1164. PKTHREAD CurrentThread;
  1165. PWCHAR CurrentPosition;
  1166. PWCHAR ListStart;
  1167. PWCHAR ListEnd;
  1168. ULONG ExecutableNameLength;
  1169. BOOLEAN FoundInList;
  1170. //
  1171. // Initialize locals.
  1172. //
  1173. PrefetcherParameters = &CcPfGlobals.Parameters;
  1174. CurrentThread = KeGetCurrentThread();
  1175. ExecutableNameLength = wcslen(ExecutableName);
  1176. FoundInList = FALSE;
  1177. //
  1178. // Get the parameters lock for read.
  1179. //
  1180. KeEnterCriticalRegionThread(CurrentThread);
  1181. ExAcquireResourceSharedLite(&PrefetcherParameters->ParametersLock, TRUE);
  1182. //
  1183. // Search for executable in hosting application list.
  1184. //
  1185. ListStart = PrefetcherParameters->Parameters.HostingApplicationList;
  1186. ListEnd = ListStart + wcslen(PrefetcherParameters->Parameters.HostingApplicationList);
  1187. for (CurrentPosition = wcsstr(ListStart, ExecutableName);
  1188. CurrentPosition != NULL;
  1189. CurrentPosition = wcsstr(CurrentPosition + 1, ExecutableName)) {
  1190. //
  1191. // We should not go beyond the limits.
  1192. //
  1193. if (CurrentPosition < ListStart || CurrentPosition >= ListEnd) {
  1194. CCPF_ASSERT(CurrentPosition >= ListStart);
  1195. CCPF_ASSERT(CurrentPosition < ListEnd);
  1196. break;
  1197. }
  1198. //
  1199. // It should be the first item in the list or be preceded by a comma.
  1200. //
  1201. if (CurrentPosition != ListStart && *(CurrentPosition - 1) != L',') {
  1202. continue;
  1203. }
  1204. //
  1205. // It should be the last item in the list or be followed by a comma.
  1206. //
  1207. if (CurrentPosition + ExecutableNameLength != ListEnd &&
  1208. CurrentPosition[ExecutableNameLength] != L',') {
  1209. continue;
  1210. }
  1211. //
  1212. // We found it in the list.
  1213. //
  1214. FoundInList = TRUE;
  1215. break;
  1216. }
  1217. //
  1218. // Release the parameters lock.
  1219. //
  1220. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  1221. KeLeaveCriticalRegionThread(CurrentThread);
  1222. //
  1223. // Return whether the executable was found in the list.
  1224. //
  1225. return FoundInList;
  1226. }