3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cc/view.c
6 * PURPOSE: Cache manager
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* NOTES **********************************************************************
13 * This is not the NT implementation of a file cache nor anything much like
16 * The general procedure for a filesystem to implement a read or write
17 * dispatch routine is as follows
19 * (1) If caching for the FCB hasn't been initiated then so do by calling
20 * CcInitializeFileCache.
22 * (2) For each 4k region which is being read or written obtain a cache page
23 * by calling CcRequestCachePage.
25 * (3) If either the page is being read or not completely written, and it is
26 * not up to date then read its data from the underlying medium. If the read
27 * fails then call CcReleaseCachePage with VALID as FALSE and return a error.
29 * (4) Copy the data into or out of the page as necessary.
31 * (5) Release the cache page
33 /* INCLUDES ******************************************************************/
37 #include <internal/debug.h>
39 #if defined (ALLOC_PRAGMA)
40 #pragma alloc_text(INIT, CcInitView)
43 /* GLOBALS *******************************************************************/
46 * If CACHE_BITMAP is defined, the cache manager uses one large memory region
47 * within the kernel address space and allocate/deallocate space from this block
48 * over a bitmap. If CACHE_BITMAP is used, the size of the mdl mapping region
49 * must be reduced (ntoskrnl\mm\mdl.c, MI_MDLMAPPING_REGION_SIZE).
51 //#define CACHE_BITMAP
53 static LIST_ENTRY DirtySegmentListHead
;
54 static LIST_ENTRY CacheSegmentListHead
;
55 static LIST_ENTRY CacheSegmentLRUListHead
;
56 static LIST_ENTRY ClosedListHead
;
57 ULONG DirtyPageCount
=0;
62 #define CI_CACHESEG_MAPPING_REGION_SIZE (128*1024*1024)
64 static PVOID CiCacheSegMappingRegionBase
= NULL
;
65 static RTL_BITMAP CiCacheSegMappingRegionAllocMap
;
66 static ULONG CiCacheSegMappingRegionHint
;
67 static KSPIN_LOCK CiCacheSegMappingRegionLock
;
70 NPAGED_LOOKASIDE_LIST iBcbLookasideList
;
71 static NPAGED_LOOKASIDE_LIST BcbLookasideList
;
72 static NPAGED_LOOKASIDE_LIST CacheSegLookasideList
;
74 static ULONG CcTimeStamp
;
75 static KEVENT LazyCloseThreadEvent
;
76 static HANDLE LazyCloseThreadHandle
;
77 static CLIENT_ID LazyCloseThreadId
;
78 static volatile BOOLEAN LazyCloseThreadShouldTerminate
;
81 /* void * alloca(size_t size); */
82 #elif defined(_MSC_VER)
83 void* _alloca(size_t size
);
85 #error Unknown compiler for alloca intrinsic stack allocation "function"
88 #if defined(DBG) || defined(KDBG)
89 static void CcRosCacheSegmentIncRefCount_ ( PCACHE_SEGMENT cs
, const char* file
, int line
)
94 DbgPrint("(%s:%i) CacheSegment %p ++RefCount=%d, Dirty %d, PageOut %d\n",
95 file
, line
, cs
, cs
->ReferenceCount
, cs
->Dirty
, cs
->PageOut
);
98 static void CcRosCacheSegmentDecRefCount_ ( PCACHE_SEGMENT cs
, const char* file
, int line
)
100 --cs
->ReferenceCount
;
101 if ( cs
->Bcb
->Trace
)
103 DbgPrint("(%s:%i) CacheSegment %p --RefCount=%d, Dirty %d, PageOut %d\n",
104 file
, line
, cs
, cs
->ReferenceCount
, cs
->Dirty
, cs
->PageOut
);
107 #define CcRosCacheSegmentIncRefCount(cs) CcRosCacheSegmentIncRefCount_(cs,__FILE__,__LINE__)
108 #define CcRosCacheSegmentDecRefCount(cs) CcRosCacheSegmentDecRefCount_(cs,__FILE__,__LINE__)
110 #define CcRosCacheSegmentIncRefCount(cs) (++((cs)->ReferenceCount))
111 #define CcRosCacheSegmentDecRefCount(cs) (--((cs)->ReferenceCount))
115 CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg
);
119 CcTryToAcquireBrokenMutex(PFAST_MUTEX FastMutex
)
121 KeEnterCriticalRegion();
122 if (InterlockedCompareExchange(&FastMutex
->Count
, 0, 1) == 1)
124 FastMutex
->Owner
= KeGetCurrentThread();
129 KeLeaveCriticalRegion();
134 /* FUNCTIONS *****************************************************************/
142 #if defined(DBG) || defined(KDBG)
144 PLIST_ENTRY current_entry
;
145 PCACHE_SEGMENT current
;
154 DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", Bcb
);
156 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
157 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
159 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
160 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
162 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
163 current_entry
= current_entry
->Flink
;
165 DPRINT1(" CacheSegment 0x%p enabled, RefCount %d, Dirty %d, PageOut %d\n",
166 current
, current
->ReferenceCount
, current
->Dirty
, current
->PageOut
);
168 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
169 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
173 DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", Bcb
);
184 CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment
)
188 Status
= WriteCacheSegment(CacheSegment
);
189 if (NT_SUCCESS(Status
))
191 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
192 KeAcquireSpinLock(&CacheSegment
->Bcb
->BcbLock
, &oldIrql
);
193 CacheSegment
->Dirty
= FALSE
;
194 RemoveEntryList(&CacheSegment
->DirtySegmentListEntry
);
195 DirtyPageCount
-= CacheSegment
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
196 CcRosCacheSegmentDecRefCount ( CacheSegment
);
197 KeReleaseSpinLock(&CacheSegment
->Bcb
->BcbLock
, oldIrql
);
198 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
205 CcRosFlushDirtyPages(ULONG Target
, PULONG Count
)
207 PLIST_ENTRY current_entry
;
208 PCACHE_SEGMENT current
;
209 ULONG PagesPerSegment
;
212 static ULONG WriteCount
[4] = {0, 0, 0, 0};
215 DPRINT("CcRosFlushDirtyPages(Target %d)\n", Target
);
219 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
221 WriteCount
[0] = WriteCount
[1];
222 WriteCount
[1] = WriteCount
[2];
223 WriteCount
[2] = WriteCount
[3];
226 NewTarget
= WriteCount
[0] + WriteCount
[1] + WriteCount
[2];
228 if (NewTarget
< DirtyPageCount
)
230 NewTarget
= (DirtyPageCount
- NewTarget
+ 3) / 4;
231 WriteCount
[0] += NewTarget
;
232 WriteCount
[1] += NewTarget
;
233 WriteCount
[2] += NewTarget
;
234 WriteCount
[3] += NewTarget
;
237 NewTarget
= WriteCount
[0];
239 Target
= max(NewTarget
, Target
);
241 current_entry
= DirtySegmentListHead
.Flink
;
242 if (current_entry
== &DirtySegmentListHead
)
244 DPRINT("No Dirty pages\n");
246 while (current_entry
!= &DirtySegmentListHead
&& Target
> 0)
248 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
249 DirtySegmentListEntry
);
250 current_entry
= current_entry
->Flink
;
252 // Locked = current->Bcb->Callbacks.AcquireForLazyWrite(current->Bcb->Context, FALSE);
253 Locked
= ExTryToAcquireResourceExclusiveLite(((FSRTL_COMMON_FCB_HEADER
*)(current
->Bcb
->FileObject
->FsContext
))->Resource
);
258 Locked
= CcTryToAcquireBrokenMutex(¤t
->Lock
);
261 // current->Bcb->Callbacks.ReleaseFromLazyWrite(current->Bcb->Context);
262 ExReleaseResourceLite(((FSRTL_COMMON_FCB_HEADER
*)(current
->Bcb
->FileObject
->FsContext
))->Resource
);
265 ASSERT(current
->Dirty
);
266 if (current
->ReferenceCount
> 1)
268 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(¤t
->Lock
);
269 // current->Bcb->Callbacks.ReleaseFromLazyWrite(current->Bcb->Context);
270 ExReleaseResourceLite(((FSRTL_COMMON_FCB_HEADER
*)(current
->Bcb
->FileObject
->FsContext
))->Resource
);
273 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
274 PagesPerSegment
= current
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
275 Status
= CcRosFlushCacheSegment(current
);
276 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(¤t
->Lock
);
277 // current->Bcb->Callbacks.ReleaseFromLazyWrite(current->Bcb->Context);
278 ExReleaseResourceLite(((FSRTL_COMMON_FCB_HEADER
*)(current
->Bcb
->FileObject
->FsContext
))->Resource
);
279 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
281 DPRINT1("CC: Failed to flush cache segment.\n");
285 (*Count
) += PagesPerSegment
;
286 Target
-= PagesPerSegment
;
288 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
289 current_entry
= DirtySegmentListHead
.Flink
;
291 if (*Count
< NewTarget
)
293 WriteCount
[1] += (NewTarget
- *Count
);
295 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
296 DPRINT("CcRosFlushDirtyPages() finished\n");
298 return(STATUS_SUCCESS
);
302 CcRosTrimCache(ULONG Target
, ULONG Priority
, PULONG NrFreed
)
304 * FUNCTION: Try to free some memory from the file cache.
306 * Target - The number of pages to be freed.
307 * Priority - The priority of free (currently unused).
308 * NrFreed - Points to a variable where the number of pages
309 * actually freed is returned.
312 PLIST_ENTRY current_entry
;
313 PCACHE_SEGMENT current
, last
= NULL
;
314 ULONG PagesPerSegment
;
319 DPRINT("CcRosTrimCache(Target %d)\n", Target
);
323 InitializeListHead(&FreeList
);
325 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
326 current_entry
= CacheSegmentLRUListHead
.Flink
;
327 while (current_entry
!= &CacheSegmentLRUListHead
&& Target
> 0)
329 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
330 CacheSegmentLRUListEntry
);
331 current_entry
= current_entry
->Flink
;
333 KeAcquireSpinLock(¤t
->Bcb
->BcbLock
, &oldIrql
);
334 if (current
->ReferenceCount
== 0)
336 RemoveEntryList(¤t
->BcbSegmentListEntry
);
337 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
338 RemoveEntryList(¤t
->CacheSegmentListEntry
);
339 RemoveEntryList(¤t
->CacheSegmentLRUListEntry
);
340 InsertHeadList(&FreeList
, ¤t
->BcbSegmentListEntry
);
341 PagesPerSegment
= current
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
342 PagesFreed
= min(PagesPerSegment
, Target
);
343 Target
-= PagesFreed
;
344 (*NrFreed
) += PagesFreed
;
348 if (last
!= current
&& current
->MappedCount
> 0 && !current
->Dirty
&& !current
->PageOut
)
353 CcRosCacheSegmentIncRefCount(current
);
355 current
->PageOut
= TRUE
;
356 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
357 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
358 for (i
= 0; i
< current
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
; i
++)
361 Page
= (PFN_TYPE
)(MmGetPhysicalAddress((char*)current
->BaseAddress
+ i
* PAGE_SIZE
).QuadPart
>> PAGE_SHIFT
);
362 Status
= MmPageOutPhysicalAddress(Page
);
363 if (!NT_SUCCESS(Status
))
368 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
369 KeAcquireSpinLock(¤t
->Bcb
->BcbLock
, &oldIrql
);
370 CcRosCacheSegmentDecRefCount(current
);
371 current
->PageOut
= FALSE
;
372 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
373 current_entry
= ¤t
->CacheSegmentLRUListEntry
;
376 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
379 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
381 while (!IsListEmpty(&FreeList
))
383 current_entry
= RemoveHeadList(&FreeList
);
384 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
385 BcbSegmentListEntry
);
386 CcRosInternalFreeCacheSegment(current
);
389 DPRINT("CcRosTrimCache() finished\n");
390 return(STATUS_SUCCESS
);
395 CcRosReleaseCacheSegment(PBCB Bcb
,
396 PCACHE_SEGMENT CacheSeg
,
401 BOOLEAN WasDirty
= CacheSeg
->Dirty
;
406 DPRINT("CcReleaseCacheSegment(Bcb 0x%p, CacheSeg 0x%p, Valid %d)\n",
407 Bcb
, CacheSeg
, Valid
);
409 CacheSeg
->Valid
= Valid
;
410 CacheSeg
->Dirty
= CacheSeg
->Dirty
|| Dirty
;
412 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
413 if (!WasDirty
&& CacheSeg
->Dirty
)
415 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
416 DirtyPageCount
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
418 RemoveEntryList(&CacheSeg
->CacheSegmentLRUListEntry
);
419 InsertTailList(&CacheSegmentLRUListHead
, &CacheSeg
->CacheSegmentLRUListEntry
);
423 CacheSeg
->MappedCount
++;
425 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
426 CcRosCacheSegmentDecRefCount(CacheSeg
);
427 if (Mapped
&& CacheSeg
->MappedCount
== 1)
429 CcRosCacheSegmentIncRefCount(CacheSeg
);
431 if (!WasDirty
&& CacheSeg
->Dirty
)
433 CcRosCacheSegmentIncRefCount(CacheSeg
);
435 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
436 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
437 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&CacheSeg
->Lock
);
439 return(STATUS_SUCCESS
);
444 CcRosLookupCacheSegment(PBCB Bcb
, ULONG FileOffset
)
446 PLIST_ENTRY current_entry
;
447 PCACHE_SEGMENT current
;
452 DPRINT("CcRosLookupCacheSegment(Bcb -x%p, FileOffset %d)\n", Bcb
, FileOffset
);
454 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
455 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
456 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
458 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
459 BcbSegmentListEntry
);
460 if (current
->FileOffset
<= FileOffset
&&
461 (current
->FileOffset
+ Bcb
->CacheSegmentSize
) > FileOffset
)
463 CcRosCacheSegmentIncRefCount(current
);
464 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
465 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(¤t
->Lock
);
468 current_entry
= current_entry
->Flink
;
470 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
476 CcRosMarkDirtyCacheSegment(PBCB Bcb
, ULONG FileOffset
)
478 PCACHE_SEGMENT CacheSeg
;
483 DPRINT("CcRosMarkDirtyCacheSegment(Bcb 0x%p, FileOffset %d)\n", Bcb
, FileOffset
);
485 CacheSeg
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
486 if (CacheSeg
== NULL
)
490 if (!CacheSeg
->Dirty
)
492 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
493 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
494 DirtyPageCount
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
495 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
499 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
500 CcRosCacheSegmentDecRefCount(CacheSeg
);
501 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
505 CacheSeg
->Dirty
= TRUE
;
506 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&CacheSeg
->Lock
);
508 return(STATUS_SUCCESS
);
513 CcRosUnmapCacheSegment(PBCB Bcb
, ULONG FileOffset
, BOOLEAN NowDirty
)
515 PCACHE_SEGMENT CacheSeg
;
521 DPRINT("CcRosUnmapCacheSegment(Bcb 0x%p, FileOffset %d, NowDirty %d)\n",
522 Bcb
, FileOffset
, NowDirty
);
524 CacheSeg
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
525 if (CacheSeg
== NULL
)
527 return(STATUS_UNSUCCESSFUL
);
530 WasDirty
= CacheSeg
->Dirty
;
531 CacheSeg
->Dirty
= CacheSeg
->Dirty
|| NowDirty
;
533 CacheSeg
->MappedCount
--;
535 if (!WasDirty
&& NowDirty
)
537 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
538 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
539 DirtyPageCount
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
540 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
543 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
544 CcRosCacheSegmentDecRefCount(CacheSeg
);
545 if (!WasDirty
&& NowDirty
)
547 CcRosCacheSegmentIncRefCount(CacheSeg
);
549 if (CacheSeg
->MappedCount
== 0)
551 CcRosCacheSegmentDecRefCount(CacheSeg
);
553 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
555 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&CacheSeg
->Lock
);
556 return(STATUS_SUCCESS
);
560 CcRosCreateCacheSegment(PBCB Bcb
,
562 PCACHE_SEGMENT
* CacheSeg
)
565 PCACHE_SEGMENT current
;
566 PCACHE_SEGMENT previous
;
567 PLIST_ENTRY current_entry
;
572 ULONG StartingOffset
;
575 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
579 DPRINT("CcRosCreateCacheSegment()\n");
581 BoundaryAddressMultiple
.QuadPart
= 0;
582 if (FileOffset
>= Bcb
->FileSize
.u
.LowPart
)
585 return STATUS_INVALID_PARAMETER
;
588 current
= ExAllocateFromNPagedLookasideList(&CacheSegLookasideList
);
589 current
->Valid
= FALSE
;
590 current
->Dirty
= FALSE
;
591 current
->PageOut
= FALSE
;
592 current
->FileOffset
= ROUND_DOWN(FileOffset
, Bcb
->CacheSegmentSize
);
594 #if defined(DBG) || defined(KDBG)
597 DPRINT1("CacheMap 0x%p: new Cache Segment: 0x%p\n", Bcb
, current
);
600 current
->MappedCount
= 0;
601 current
->DirtySegmentListEntry
.Flink
= NULL
;
602 current
->DirtySegmentListEntry
.Blink
= NULL
;
603 current
->ReferenceCount
= 1;
604 ExInitializeFastMutex(¤t
->Lock
);
605 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(¤t
->Lock
);
606 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
609 /* There is window between the call to CcRosLookupCacheSegment
610 * and CcRosCreateCacheSegment. We must check if a segment on
611 * the fileoffset exist. If there exist a segment, we release
612 * our new created segment and return the existing one.
614 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
615 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
617 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
619 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
620 BcbSegmentListEntry
);
621 if (current
->FileOffset
<= FileOffset
&&
622 (current
->FileOffset
+ Bcb
->CacheSegmentSize
) > FileOffset
)
624 CcRosCacheSegmentIncRefCount(current
);
625 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
626 #if defined(DBG) || defined(KDBG)
629 DPRINT1("CacheMap 0x%p: deleting newly created Cache Segment 0x%p ( found existing one 0x%p )\n",
635 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&(*CacheSeg
)->Lock
);
636 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
637 ExFreeToNPagedLookasideList(&CacheSegLookasideList
, *CacheSeg
);
639 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(¤t
->Lock
);
640 return STATUS_SUCCESS
;
642 if (current
->FileOffset
< FileOffset
)
644 if (previous
== NULL
)
650 if (previous
->FileOffset
< current
->FileOffset
)
656 current_entry
= current_entry
->Flink
;
658 /* There was no existing segment. */
662 InsertHeadList(&previous
->BcbSegmentListEntry
, ¤t
->BcbSegmentListEntry
);
666 InsertHeadList(&Bcb
->BcbSegmentListHead
, ¤t
->BcbSegmentListEntry
);
668 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
669 InsertTailList(&CacheSegmentListHead
, ¤t
->CacheSegmentListEntry
);
670 InsertTailList(&CacheSegmentLRUListHead
, ¤t
->CacheSegmentLRUListEntry
);
671 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
673 KeAcquireSpinLock(&CiCacheSegMappingRegionLock
, &oldIrql
);
675 StartingOffset
= RtlFindClearBitsAndSet(&CiCacheSegMappingRegionAllocMap
, Bcb
->CacheSegmentSize
/ PAGE_SIZE
, CiCacheSegMappingRegionHint
);
677 if (StartingOffset
== 0xffffffff)
679 DPRINT1("Out of CacheSeg mapping space\n");
683 current
->BaseAddress
= CiCacheSegMappingRegionBase
+ StartingOffset
* PAGE_SIZE
;
685 if (CiCacheSegMappingRegionHint
== StartingOffset
)
687 CiCacheSegMappingRegionHint
+= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
690 KeReleaseSpinLock(&CiCacheSegMappingRegionLock
, oldIrql
);
692 MmLockAddressSpace(MmGetKernelAddressSpace());
693 current
->BaseAddress
= NULL
;
694 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
695 MEMORY_AREA_CACHE_SEGMENT
,
696 ¤t
->BaseAddress
,
697 Bcb
->CacheSegmentSize
,
699 (PMEMORY_AREA
*)¤t
->MemoryArea
,
702 BoundaryAddressMultiple
);
703 MmUnlockAddressSpace(MmGetKernelAddressSpace());
704 if (!NT_SUCCESS(Status
))
709 Pfn
= alloca(sizeof(PFN_TYPE
) * (Bcb
->CacheSegmentSize
/ PAGE_SIZE
));
710 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++)
712 Status
= MmRequestPageMemoryConsumer(MC_CACHE
, TRUE
, &Pfn
[i
]);
713 if (!NT_SUCCESS(Status
))
718 Status
= MmCreateVirtualMapping(NULL
,
719 current
->BaseAddress
,
722 Bcb
->CacheSegmentSize
/ PAGE_SIZE
);
723 if (!NT_SUCCESS(Status
))
727 return(STATUS_SUCCESS
);
732 CcRosGetCacheSegmentChain(PBCB Bcb
,
735 PCACHE_SEGMENT
* CacheSeg
)
737 PCACHE_SEGMENT current
;
739 PCACHE_SEGMENT
* CacheSegList
;
740 PCACHE_SEGMENT Previous
= NULL
;
744 DPRINT("CcRosGetCacheSegmentChain()\n");
746 Length
= ROUND_UP(Length
, Bcb
->CacheSegmentSize
);
748 #if defined(__GNUC__)
749 CacheSegList
= alloca(sizeof(PCACHE_SEGMENT
) *
750 (Length
/ Bcb
->CacheSegmentSize
));
751 #elif defined(_MSC_VER)
752 CacheSegList
= _alloca(sizeof(PCACHE_SEGMENT
) *
753 (Length
/ Bcb
->CacheSegmentSize
));
755 #error Unknown compiler for alloca intrinsic stack allocation "function"
759 * Look for a cache segment already mapping the same data.
761 for (i
= 0; i
< (Length
/ Bcb
->CacheSegmentSize
); i
++)
763 ULONG CurrentOffset
= FileOffset
+ (i
* Bcb
->CacheSegmentSize
);
764 current
= CcRosLookupCacheSegment(Bcb
, CurrentOffset
);
767 CacheSegList
[i
] = current
;
771 CcRosCreateCacheSegment(Bcb
, CurrentOffset
, ¤t
);
772 CacheSegList
[i
] = current
;
776 for (i
= 0; i
< (Length
/ Bcb
->CacheSegmentSize
); i
++)
780 *CacheSeg
= CacheSegList
[i
];
781 Previous
= CacheSegList
[i
];
785 Previous
->NextInChain
= CacheSegList
[i
];
786 Previous
= CacheSegList
[i
];
790 Previous
->NextInChain
= NULL
;
792 return(STATUS_SUCCESS
);
797 CcRosGetCacheSegment(PBCB Bcb
,
802 PCACHE_SEGMENT
* CacheSeg
)
804 PCACHE_SEGMENT current
;
809 DPRINT("CcRosGetCacheSegment()\n");
812 * Look for a cache segment already mapping the same data.
814 current
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
818 * Otherwise create a new segment.
820 Status
= CcRosCreateCacheSegment(Bcb
, FileOffset
, ¤t
);
821 if (!NT_SUCCESS(Status
))
827 * Return information about the segment to the caller.
829 *UptoDate
= current
->Valid
;
830 *BaseAddress
= current
->BaseAddress
;
831 DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress
);
833 *BaseOffset
= current
->FileOffset
;
834 return(STATUS_SUCCESS
);
838 CcRosRequestCacheSegment(PBCB Bcb
,
842 PCACHE_SEGMENT
* CacheSeg
)
844 * FUNCTION: Request a page mapping for a BCB
851 if ((FileOffset
% Bcb
->CacheSegmentSize
) != 0)
853 CPRINT("Bad fileoffset %x should be multiple of %x",
854 FileOffset
, Bcb
->CacheSegmentSize
);
858 return(CcRosGetCacheSegment(Bcb
,
868 CcFreeCachePage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
869 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
871 ASSERT(SwapEntry
== 0);
874 MmReleasePageMemoryConsumer(MC_CACHE
, Page
);
879 CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg
)
881 * FUNCTION: Releases a cache segment associated with a BCB
891 DPRINT("Freeing cache segment 0x%p\n", CacheSeg
);
892 #if defined(DBG) || defined(KDBG)
893 if ( CacheSeg
->Bcb
->Trace
)
895 DPRINT1("CacheMap 0x%p: deleting Cache Segment: 0x%p\n", CacheSeg
->Bcb
, CacheSeg
);
899 RegionSize
= CacheSeg
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
901 /* Unmap all the pages. */
902 for (i
= 0; i
< RegionSize
; i
++)
904 MmDeleteVirtualMapping(NULL
,
905 CacheSeg
->BaseAddress
+ (i
* PAGE_SIZE
),
909 MmReleasePageMemoryConsumer(MC_CACHE
, Page
);
912 KeAcquireSpinLock(&CiCacheSegMappingRegionLock
, &oldIrql
);
913 /* Deallocate all the pages used. */
914 Base
= (ULONG
)(CacheSeg
->BaseAddress
- CiCacheSegMappingRegionBase
) / PAGE_SIZE
;
916 RtlClearBits(&CiCacheSegMappingRegionAllocMap
, Base
, RegionSize
);
918 CiCacheSegMappingRegionHint
= min (CiCacheSegMappingRegionHint
, Base
);
920 KeReleaseSpinLock(&CiCacheSegMappingRegionLock
, oldIrql
);
922 MmLockAddressSpace(MmGetKernelAddressSpace());
923 MmFreeMemoryArea(MmGetKernelAddressSpace(),
924 CacheSeg
->MemoryArea
,
927 MmUnlockAddressSpace(MmGetKernelAddressSpace());
929 ExFreeToNPagedLookasideList(&CacheSegLookasideList
, CacheSeg
);
930 return(STATUS_SUCCESS
);
935 CcRosFreeCacheSegment(PBCB Bcb
, PCACHE_SEGMENT CacheSeg
)
942 DPRINT("CcRosFreeCacheSegment(Bcb 0x%p, CacheSeg 0x%p)\n",
945 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
946 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
947 RemoveEntryList(&CacheSeg
->BcbSegmentListEntry
);
948 RemoveEntryList(&CacheSeg
->CacheSegmentListEntry
);
949 RemoveEntryList(&CacheSeg
->CacheSegmentLRUListEntry
);
952 RemoveEntryList(&CacheSeg
->DirtySegmentListEntry
);
953 DirtyPageCount
-= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
956 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
957 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
959 Status
= CcRosInternalFreeCacheSegment(CacheSeg
);
967 CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointers
,
968 IN PLARGE_INTEGER FileOffset OPTIONAL
,
970 OUT PIO_STATUS_BLOCK IoStatus
)
973 LARGE_INTEGER Offset
;
974 PCACHE_SEGMENT current
;
978 DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %d, IoStatus 0x%p)\n",
979 SectionObjectPointers
, FileOffset
, Length
, IoStatus
);
981 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
983 Bcb
= (PBCB
)SectionObjectPointers
->SharedCacheMap
;
987 Offset
= *FileOffset
;
991 Offset
.QuadPart
= (LONGLONG
)0;
992 Length
= Bcb
->FileSize
.u
.LowPart
;
997 IoStatus
->Status
= STATUS_SUCCESS
;
998 IoStatus
->Information
= 0;
1003 current
= CcRosLookupCacheSegment (Bcb
, Offset
.u
.LowPart
);
1004 if (current
!= NULL
)
1008 Status
= CcRosFlushCacheSegment(current
);
1009 if (!NT_SUCCESS(Status
) && IoStatus
!= NULL
)
1011 IoStatus
->Status
= Status
;
1014 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
1015 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(¤t
->Lock
);
1016 CcRosCacheSegmentDecRefCount(current
);
1017 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
1020 Offset
.QuadPart
+= Bcb
->CacheSegmentSize
;
1021 if (Length
> Bcb
->CacheSegmentSize
)
1023 Length
-= Bcb
->CacheSegmentSize
;
1035 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
1042 CcRosDeleteFileCache(PFILE_OBJECT FileObject
, PBCB Bcb
)
1044 * FUNCTION: Releases the BCB associated with a file object
1047 PLIST_ENTRY current_entry
;
1048 PCACHE_SEGMENT current
;
1050 LIST_ENTRY FreeList
;
1056 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
1058 CcFlushCache(FileObject
->SectionObjectPointer
, NULL
, 0, NULL
);
1060 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
1062 if (Bcb
->RefCount
== 0)
1064 if (Bcb
->BcbRemoveListEntry
.Flink
!= NULL
)
1066 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1067 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1070 FileObject
->SectionObjectPointer
->SharedCacheMap
= NULL
;
1073 * Release all cache segments.
1075 InitializeListHead(&FreeList
);
1076 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
1077 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
1078 while (!IsListEmpty(&Bcb
->BcbSegmentListHead
))
1080 current_entry
= RemoveTailList(&Bcb
->BcbSegmentListHead
);
1081 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
1082 RemoveEntryList(¤t
->CacheSegmentListEntry
);
1083 RemoveEntryList(¤t
->CacheSegmentLRUListEntry
);
1086 RemoveEntryList(¤t
->DirtySegmentListEntry
);
1087 DirtyPageCount
-= Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
1088 DPRINT1("Freeing dirty segment\n");
1090 InsertHeadList(&FreeList
, ¤t
->BcbSegmentListEntry
);
1092 #if defined(DBG) || defined(KDBG)
1095 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
1097 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
1098 ObDereferenceObject (Bcb
->FileObject
);
1100 while (!IsListEmpty(&FreeList
))
1102 current_entry
= RemoveTailList(&FreeList
);
1103 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
1104 Status
= CcRosInternalFreeCacheSegment(current
);
1106 ExFreeToNPagedLookasideList(&BcbLookasideList
, Bcb
);
1107 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
1109 return(STATUS_SUCCESS
);
1114 CcRosReferenceCache(PFILE_OBJECT FileObject
)
1117 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
1118 Bcb
= (PBCB
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
1120 if (Bcb
->RefCount
== 0)
1122 ASSERT(Bcb
->BcbRemoveListEntry
.Flink
!= NULL
);
1123 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1124 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1129 ASSERT(Bcb
->BcbRemoveListEntry
.Flink
== NULL
);
1132 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
1137 CcRosSetRemoveOnClose(PSECTION_OBJECT_POINTERS SectionObjectPointer
)
1140 DPRINT("CcRosSetRemoveOnClose()\n");
1141 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
1142 Bcb
= (PBCB
)SectionObjectPointer
->SharedCacheMap
;
1145 Bcb
->RemoveOnClose
= TRUE
;
1146 if (Bcb
->RefCount
== 0)
1148 CcRosDeleteFileCache(Bcb
->FileObject
, Bcb
);
1151 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
1157 CcRosDereferenceCache(PFILE_OBJECT FileObject
)
1160 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
1161 Bcb
= (PBCB
)FileObject
->SectionObjectPointer
->SharedCacheMap
;
1163 if (Bcb
->RefCount
> 0)
1166 if (Bcb
->RefCount
== 0)
1168 MmFreeSectionSegments(Bcb
->FileObject
);
1169 if (Bcb
->RemoveOnClose
)
1171 CcRosDeleteFileCache(FileObject
, Bcb
);
1175 Bcb
->TimeStamp
= CcTimeStamp
;
1176 InsertHeadList(&ClosedListHead
, &Bcb
->BcbRemoveListEntry
);
1180 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
1184 CcRosReleaseFileCache(PFILE_OBJECT FileObject
)
1186 * FUNCTION: Called by the file system when a handle to a file object
1192 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
1194 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
1196 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1197 if (FileObject
->PrivateCacheMap
!= NULL
)
1199 FileObject
->PrivateCacheMap
= NULL
;
1200 if (Bcb
->RefCount
> 0)
1203 if (Bcb
->RefCount
== 0)
1205 MmFreeSectionSegments(Bcb
->FileObject
);
1206 if (Bcb
->RemoveOnClose
)
1208 CcRosDeleteFileCache(FileObject
, Bcb
);
1212 Bcb
->TimeStamp
= CcTimeStamp
;
1213 InsertHeadList(&ClosedListHead
, &Bcb
->BcbRemoveListEntry
);
1219 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
1220 return(STATUS_SUCCESS
);
1225 CcTryToInitializeFileCache(PFILE_OBJECT FileObject
)
1230 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
1232 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1235 Status
= STATUS_UNSUCCESSFUL
;
1239 if (FileObject
->PrivateCacheMap
== NULL
)
1241 FileObject
->PrivateCacheMap
= Bcb
;
1244 if (Bcb
->BcbRemoveListEntry
.Flink
!= NULL
)
1246 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1247 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1249 Status
= STATUS_SUCCESS
;
1251 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
1258 CcRosInitializeFileCache(PFILE_OBJECT FileObject
,
1259 ULONG CacheSegmentSize
)
1261 * FUNCTION: Initializes a BCB for a file object
1266 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1267 DPRINT("CcRosInitializeFileCache(FileObject 0x%p, Bcb 0x%p, CacheSegmentSize %d)\n",
1268 FileObject
, Bcb
, CacheSegmentSize
);
1270 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
1273 Bcb
= ExAllocateFromNPagedLookasideList(&BcbLookasideList
);
1276 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
1277 return(STATUS_UNSUCCESSFUL
);
1279 memset(Bcb
, 0, sizeof(BCB
));
1280 ObReferenceObjectByPointer(FileObject
,
1284 Bcb
->FileObject
= FileObject
;
1285 Bcb
->CacheSegmentSize
= CacheSegmentSize
;
1286 if (FileObject
->FsContext
)
1288 Bcb
->AllocationSize
=
1289 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->AllocationSize
;
1291 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
;
1293 KeInitializeSpinLock(&Bcb
->BcbLock
);
1294 InitializeListHead(&Bcb
->BcbSegmentListHead
);
1295 FileObject
->SectionObjectPointer
->SharedCacheMap
= Bcb
;
1297 if (FileObject
->PrivateCacheMap
== NULL
)
1299 FileObject
->PrivateCacheMap
= Bcb
;
1302 if (Bcb
->BcbRemoveListEntry
.Flink
!= NULL
)
1304 RemoveEntryList(&Bcb
->BcbRemoveListEntry
);
1305 Bcb
->BcbRemoveListEntry
.Flink
= NULL
;
1307 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
1309 return(STATUS_SUCCESS
);
1315 PFILE_OBJECT STDCALL
1316 CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointers
)
1319 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
1321 Bcb
= (PBCB
)SectionObjectPointers
->SharedCacheMap
;
1323 return Bcb
->FileObject
;
1329 CmLazyCloseThreadMain(PVOID Ignored
)
1331 LARGE_INTEGER Timeout
;
1332 PLIST_ENTRY current_entry
;
1334 ULONG RemoveTimeStamp
;
1337 KeQuerySystemTime (&Timeout
);
1341 Timeout
.QuadPart
+= (LONGLONG
)100000000; // 10sec
1342 Status
= KeWaitForSingleObject(&LazyCloseThreadEvent
,
1348 DPRINT("LazyCloseThreadMain %d\n", CcTimeStamp
);
1350 if (!NT_SUCCESS(Status
))
1352 DbgPrint("LazyCloseThread: Wait failed\n");
1356 if (LazyCloseThreadShouldTerminate
)
1358 DbgPrint("LazyCloseThread: Terminating\n");
1362 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&ViewLock
);
1364 if (CcTimeStamp
>= 30)
1366 RemoveTimeStamp
= CcTimeStamp
- 30; /* 5min = 10sec * 30 */
1367 while (!IsListEmpty(&ClosedListHead
))
1369 current_entry
= ClosedListHead
.Blink
;
1370 current
= CONTAINING_RECORD(current_entry
, BCB
, BcbRemoveListEntry
);
1371 if (current
->TimeStamp
>= RemoveTimeStamp
)
1375 CcRosDeleteFileCache(current
->FileObject
, current
);
1378 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&ViewLock
);
1390 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
1395 DPRINT("CcInitView()\n");
1397 BoundaryAddressMultiple
.QuadPart
= 0;
1398 CiCacheSegMappingRegionHint
= 0;
1399 CiCacheSegMappingRegionBase
= NULL
;
1401 MmLockAddressSpace(MmGetKernelAddressSpace());
1403 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
1404 MEMORY_AREA_CACHE_SEGMENT
,
1405 &CiCacheSegMappingRegionBase
,
1406 CI_CACHESEG_MAPPING_REGION_SIZE
,
1411 BoundaryAddressMultiple
);
1412 MmUnlockAddressSpace(MmGetKernelAddressSpace());
1413 if (!NT_SUCCESS(Status
))
1418 Buffer
= ExAllocatePool(NonPagedPool
, CI_CACHESEG_MAPPING_REGION_SIZE
/ (PAGE_SIZE
* 8));
1420 RtlInitializeBitMap(&CiCacheSegMappingRegionAllocMap
, Buffer
, CI_CACHESEG_MAPPING_REGION_SIZE
/ PAGE_SIZE
);
1421 RtlClearAllBits(&CiCacheSegMappingRegionAllocMap
);
1423 KeInitializeSpinLock(&CiCacheSegMappingRegionLock
);
1425 InitializeListHead(&CacheSegmentListHead
);
1426 InitializeListHead(&DirtySegmentListHead
);
1427 InitializeListHead(&CacheSegmentLRUListHead
);
1428 InitializeListHead(&ClosedListHead
);
1429 ExInitializeFastMutex(&ViewLock
);
1430 ExInitializeNPagedLookasideList (&iBcbLookasideList
,
1434 sizeof(INTERNAL_BCB
),
1437 ExInitializeNPagedLookasideList (&BcbLookasideList
,
1444 ExInitializeNPagedLookasideList (&CacheSegLookasideList
,
1448 sizeof(CACHE_SEGMENT
),
1452 MmInitializeMemoryConsumer(MC_CACHE
, CcRosTrimCache
);
1454 CcInitCacheZeroPage();
1457 LazyCloseThreadShouldTerminate
= FALSE
;
1458 KeInitializeEvent (&LazyCloseThreadEvent
, SynchronizationEvent
, FALSE
);
1459 Status
= PsCreateSystemThread(&LazyCloseThreadHandle
,
1464 (PKSTART_ROUTINE
)CmLazyCloseThreadMain
,
1466 if (NT_SUCCESS(Status
))
1468 Priority
= LOW_REALTIME_PRIORITY
;
1469 NtSetInformationThread(LazyCloseThreadHandle
,