ReactOS.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2024
December
November
October
September
August
July
June
May
April
March
February
January
2023
December
November
October
September
August
July
June
May
April
March
February
January
2022
December
November
October
September
August
July
June
May
April
March
February
January
2021
December
November
October
September
August
July
June
May
April
March
February
January
2020
December
November
October
September
August
July
June
May
April
March
February
January
2019
December
November
October
September
August
July
June
May
April
March
February
January
2018
December
November
October
September
August
July
June
May
April
March
February
January
2017
December
November
October
September
August
July
June
May
April
March
February
January
2016
December
November
October
September
August
July
June
May
April
March
February
January
2015
December
November
October
September
August
July
June
May
April
March
February
January
2014
December
November
October
September
August
July
June
May
April
March
February
January
2013
December
November
October
September
August
July
June
May
April
March
February
January
2012
December
November
October
September
August
July
June
May
April
March
February
January
2011
December
November
October
September
August
July
June
May
April
March
February
January
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008
December
November
October
September
August
July
June
May
April
March
February
January
2007
December
November
October
September
August
July
June
May
April
March
February
January
2006
December
November
October
September
August
July
June
May
April
March
February
January
2005
December
November
October
September
August
July
June
May
April
March
February
January
2004
December
November
October
September
August
July
June
May
April
March
February
List overview
Download
Ros-diffs
January 2018
----- 2024 -----
December 2024
November 2024
October 2024
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
----- 2012 -----
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
May 2012
April 2012
March 2012
February 2012
January 2012
----- 2011 -----
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
----- 2010 -----
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
----- 2009 -----
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
----- 2008 -----
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
----- 2007 -----
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
----- 2006 -----
December 2006
November 2006
October 2006
September 2006
August 2006
July 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
----- 2005 -----
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
May 2005
April 2005
March 2005
February 2005
January 2005
----- 2004 -----
December 2004
November 2004
October 2004
September 2004
August 2004
July 2004
June 2004
May 2004
April 2004
March 2004
February 2004
ros-diffs@reactos.org
37 participants
372 discussions
Start a n
N
ew thread
01/01: [NTOSKRNL] Make lazy writer thread run with higher priority.
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=4a910a12cce2648652617…
commit 4a910a12cce264865261718ca8fe462cba45e4c0 Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Wed Jan 24 10:09:19 2018 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Wed Jan 24 10:09:19 2018 +0100 [NTOSKRNL] Make lazy writer thread run with higher priority. CORE-14248 --- ntoskrnl/cc/view.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ntoskrnl/cc/view.c b/ntoskrnl/cc/view.c index 2bab26c446..5588a912db 100644 --- a/ntoskrnl/cc/view.c +++ b/ntoskrnl/cc/view.c @@ -1387,6 +1387,7 @@ CcInitView ( { HANDLE LazyWriter; NTSTATUS Status; + KPRIORITY Priority; OBJECT_ATTRIBUTES ObjectAttributes; DPRINT("CcInitView()\n"); @@ -1458,6 +1459,13 @@ CcInitView ( return FALSE; } + Priority = 27; + Status = NtSetInformationThread(LazyWriter, + ThreadPriority, + &Priority, + sizeof(Priority)); + ASSERT(NT_SUCCESS(Status)); + /* Handle is not needed */ ObCloseHandle(LazyWriter, KernelMode);
6 years, 11 months
1
0
0
0
05/05: [NTOSKRNL] Implement per-file dirty page threshold. Namely, implement CcSetDirtyPageThreshold() and add support for it in CcCanIWrite().
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f93acd806aaff5a469820…
commit f93acd806aaff5a4698205ec8b432194b14a4f40 Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Jan 23 23:23:32 2018 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Jan 23 23:25:26 2018 +0100 [NTOSKRNL] Implement per-file dirty page threshold. Namely, implement CcSetDirtyPageThreshold() and add support for it in CcCanIWrite(). Also added my name in the headers of the few files I touched tonight. CORE-14235 --- ntoskrnl/cc/cacheman.c | 18 +++++++++++++-- ntoskrnl/cc/copy.c | 52 ++++++++++++++++++++++++++++++++++++++++-- ntoskrnl/cc/view.c | 2 ++ ntoskrnl/include/internal/cc.h | 1 + 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/ntoskrnl/cc/cacheman.c b/ntoskrnl/cc/cacheman.c index 2c2c2238c9..8303dd9dd8 100644 --- a/ntoskrnl/cc/cacheman.c +++ b/ntoskrnl/cc/cacheman.c @@ -5,6 +5,7 @@ * PURPOSE: Cache manager * * PROGRAMMERS: David Welch (welch(a)cwcom.net) + * Pierre Schweitzer (pierre(a)reactos.org) */ /* INCLUDES *****************************************************************/ @@ -140,7 +141,7 @@ CcSetBcbOwnerPointer ( } /* - * @unimplemented + * @implemented */ VOID NTAPI @@ -149,10 +150,23 @@ CcSetDirtyPageThreshold ( IN ULONG DirtyPageThreshold ) { + PFSRTL_COMMON_FCB_HEADER Fcb; + PROS_SHARED_CACHE_MAP SharedCacheMap; + CCTRACE(CC_API_DEBUG, "FileObject=%p DirtyPageThreshold=%lu\n", FileObject, DirtyPageThreshold); - UNIMPLEMENTED; + SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; + if (SharedCacheMap != NULL) + { + SharedCacheMap->DirtyPageThreshold = DirtyPageThreshold; + } + + Fcb = FileObject->FsContext; + if (!BooleanFlagOn(Fcb->Flags, FSRTL_FLAG_LIMIT_MODIFIED_PAGES)) + { + SetFlag(Fcb->Flags, FSRTL_FLAG_LIMIT_MODIFIED_PAGES); + } } /* diff --git a/ntoskrnl/cc/copy.c b/ntoskrnl/cc/copy.c index 4c68bf036b..db6f0f4920 100644 --- a/ntoskrnl/cc/copy.c +++ b/ntoskrnl/cc/copy.c @@ -4,7 +4,8 @@ * FILE: ntoskrnl/cc/copy.c * PURPOSE: Implements cache managers copy interface * - * PROGRAMMERS: + * PROGRAMMERS: Some people? + * Pierre Schweitzer (pierre(a)reactos.org) */ /* INCLUDES ******************************************************************/ @@ -375,6 +376,12 @@ CcCanIWrite ( IN BOOLEAN Wait, IN BOOLEAN Retrying) { + KIRQL OldIrql; + ULONG DirtyPages; + PLIST_ENTRY ListEntry; + PFSRTL_COMMON_FCB_HEADER Fcb; + PROS_SHARED_CACHE_MAP SharedCacheMap; + CCTRACE(CC_API_DEBUG, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n", FileObject, BytesToWrite, Wait, Retrying); @@ -392,7 +399,48 @@ CcCanIWrite ( return FALSE; } - /* FIXME: Handle per-file threshold */ + /* Is there a limit per file object? */ + Fcb = FileObject->FsContext; + SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; + if (!BooleanFlagOn(Fcb->Flags, FSRTL_FLAG_LIMIT_MODIFIED_PAGES) || + SharedCacheMap->DirtyPageThreshold == 0) + { + /* Nope, so that's fine, allow write operation */ + return TRUE; + } + + /* There's a limit, start counting dirty pages */ + DirtyPages = 0; + KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); + for (ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink; + ListEntry != &SharedCacheMap->CacheMapVacbListHead; + ListEntry = ListEntry->Flink) + { + PROS_VACB Vacb; + + Vacb = CONTAINING_RECORD(ListEntry, + ROS_VACB, + CacheMapVacbListEntry); + if (Vacb->Dirty) + { + DirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; + } + } + KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); + + /* Is dirty page count above local threshold? */ + if (DirtyPages > SharedCacheMap->DirtyPageThreshold) + { + return FALSE; + } + + /* We cannot write if dirty pages count will bring use above + * XXX: Might not be accurate + */ + if (DirtyPages + (BytesToWrite / PAGE_SIZE) > SharedCacheMap->DirtyPageThreshold) + { + return FALSE; + } return TRUE; } diff --git a/ntoskrnl/cc/view.c b/ntoskrnl/cc/view.c index 61036b0d99..2bab26c446 100644 --- a/ntoskrnl/cc/view.c +++ b/ntoskrnl/cc/view.c @@ -5,6 +5,7 @@ * PURPOSE: Cache manager * * PROGRAMMERS: David Welch (welch(a)mcmail.com) + * Pierre Schweitzer (pierre(a)reactos.org) */ /* NOTES ********************************************************************** @@ -1333,6 +1334,7 @@ CcRosInitializeFileCache ( SharedCacheMap->SectionSize = FileSizes->AllocationSize; SharedCacheMap->FileSize = FileSizes->FileSize; SharedCacheMap->PinAccess = PinAccess; + SharedCacheMap->DirtyPageThreshold = 0; KeInitializeSpinLock(&SharedCacheMap->CacheMapLock); InitializeListHead(&SharedCacheMap->CacheMapVacbListHead); FileObject->SectionObjectPointer->SharedCacheMap = SharedCacheMap; diff --git a/ntoskrnl/include/internal/cc.h b/ntoskrnl/include/internal/cc.h index 05eb53fec7..2699dfcf43 100644 --- a/ntoskrnl/include/internal/cc.h +++ b/ntoskrnl/include/internal/cc.h @@ -159,6 +159,7 @@ typedef struct _ROS_SHARED_CACHE_MAP PVOID LazyWriteContext; KSPIN_LOCK CacheMapLock; ULONG OpenCount; + ULONG DirtyPageThreshold; #if DBG BOOLEAN Trace; /* enable extra trace output for this cache map and it's VACBs */ #endif
6 years, 11 months
1
0
0
0
04/05: [NTOSKRNL] Unexpected cleanup
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=389f683026bf9849c3c85…
commit 389f683026bf9849c3c85e12aac2363bdfd48672 Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Jan 23 23:01:07 2018 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Jan 23 23:25:26 2018 +0100 [NTOSKRNL] Unexpected cleanup --- ntoskrnl/cc/fs.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ntoskrnl/cc/fs.c b/ntoskrnl/cc/fs.c index 76a073af1b..d068f96eb2 100644 --- a/ntoskrnl/cc/fs.c +++ b/ntoskrnl/cc/fs.c @@ -13,14 +13,9 @@ #define NDEBUG #include <debug.h> -#ifndef VACB_MAPPING_GRANULARITY -#define VACB_MAPPING_GRANULARITY (256 * 1024) -#endif - /* GLOBALS *****************************************************************/ extern KGUARDED_MUTEX ViewLock; -extern ULONG CcTotalDirtyPages; NTSTATUS CcRosInternalFreeVacb(PROS_VACB Vacb);
6 years, 11 months
1
0
0
0
03/05: [NTOSKRNL] Implement support for deferred writes in Cc. Namely, implement CcCanIWrite() (very basic, and likely wrong). And implement CcDeferWrite() which will queue the write operation.
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=9a07c71eef55f16fd64ad…
commit 9a07c71eef55f16fd64ad01821d7798f8f89944b Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Jan 23 22:56:23 2018 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Jan 23 23:25:26 2018 +0100 [NTOSKRNL] Implement support for deferred writes in Cc. Namely, implement CcCanIWrite() (very basic, and likely wrong). And implement CcDeferWrite() which will queue the write operation. In CciLazyWriter() (which may be renamed CcWorkerThread() ;-)), handle the queued write operations one by one. This is likely not to be accurate, but, given we have only on FS supporting this for now (NFS / RDBSS / Shares), this is OK. CORE-14235 --- ntoskrnl/cc/copy.c | 53 ++++++++++++++++++++++++++++++++++++++++-- ntoskrnl/cc/view.c | 35 ++++++++++++++++++++++++++++ ntoskrnl/include/internal/cc.h | 15 ++++++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/ntoskrnl/cc/copy.c b/ntoskrnl/cc/copy.c index dadae020c7..4c68bf036b 100644 --- a/ntoskrnl/cc/copy.c +++ b/ntoskrnl/cc/copy.c @@ -378,6 +378,22 @@ CcCanIWrite ( CCTRACE(CC_API_DEBUG, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n", FileObject, BytesToWrite, Wait, Retrying); + /* We cannot write if dirty pages count is above threshold */ + if (CcTotalDirtyPages > CcDirtyPageThreshold) + { + return FALSE; + } + + /* We cannot write if dirty pages count will bring use above + * XXX: Might not be accurate + */ + if (CcTotalDirtyPages + (BytesToWrite / PAGE_SIZE) > CcDirtyPageThreshold) + { + return FALSE; + } + + /* FIXME: Handle per-file threshold */ + return TRUE; } @@ -442,7 +458,7 @@ CcCopyWrite ( } /* - * @unimplemented + * @implemented */ VOID NTAPI @@ -454,10 +470,43 @@ CcDeferWrite ( IN ULONG BytesToWrite, IN BOOLEAN Retrying) { + PROS_DEFERRED_WRITE_CONTEXT Context; + CCTRACE(CC_API_DEBUG, "FileObject=%p PostRoutine=%p Context1=%p Context2=%p BytesToWrite=%lu Retrying=%d\n", FileObject, PostRoutine, Context1, Context2, BytesToWrite, Retrying); - PostRoutine(Context1, Context2); + /* Try to allocate a context for queueing the write operation */ + Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(ROS_DEFERRED_WRITE_CONTEXT), 'CcDw'); + /* If it failed, immediately execute the operation! */ + if (Context == NULL) + { + PostRoutine(Context1, Context2); + return; + } + + /* Otherwise, initialize the context */ + Context->FileObject = FileObject; + Context->PostRoutine = PostRoutine; + Context->Context1 = Context1; + Context->Context2 = Context2; + Context->BytesToWrite = BytesToWrite; + Context->Retrying = Retrying; + + /* And queue it */ + if (Retrying) + { + /* To the top, if that's a retry */ + ExInterlockedInsertHeadList(&CcDeferredWrites, + &Context->CcDeferredWritesEntry, + &CcDeferredWriteSpinLock); + } + else + { + /* To the bottom, if that's a first time */ + ExInterlockedInsertTailList(&CcDeferredWrites, + &Context->CcDeferredWritesEntry, + &CcDeferredWriteSpinLock); + } } /* diff --git a/ntoskrnl/cc/view.c b/ntoskrnl/cc/view.c index 465fffa595..61036b0d99 100644 --- a/ntoskrnl/cc/view.c +++ b/ntoskrnl/cc/view.c @@ -60,9 +60,13 @@ ULONG CcLazyWriteIos = 0; /* Internal vars (MS): * - Threshold above which lazy writer will start action * - Amount of dirty pages + * - List for deferred writes + * - Spinlock when dealing with the deferred list */ ULONG CcDirtyPageThreshold = 0; ULONG CcTotalDirtyPages = 0; +LIST_ENTRY CcDeferredWrites; +KSPIN_LOCK CcDeferredWriteSpinLock; /* Internal vars (ROS): * - Event to notify lazy writer to shutdown @@ -308,6 +312,7 @@ CciLazyWriter(PVOID Unused) while (TRUE) { NTSTATUS Status; + PLIST_ENTRY ListEntry; ULONG Target, Count = 0; /* One per second or until we have to stop */ @@ -342,6 +347,34 @@ CciLazyWriter(PVOID Unused) /* Inform people waiting on us that we're done */ KeSetEvent(&iLazyWriterNotify, IO_DISK_INCREMENT, FALSE); + + /* Likely not optimal, but let's handle one deferred write now! */ + ListEntry = ExInterlockedRemoveHeadList(&CcDeferredWrites, &CcDeferredWriteSpinLock); + if (ListEntry != NULL) + { + PROS_DEFERRED_WRITE_CONTEXT Context; + + /* Extract the context */ + Context = CONTAINING_RECORD(ListEntry, ROS_DEFERRED_WRITE_CONTEXT, CcDeferredWritesEntry); + + /* Can we write now? */ + if (CcCanIWrite(Context->FileObject, Context->BytesToWrite, FALSE, Context->Retrying)) + { + /* Yes! Do it, and destroy the associated context */ + Context->PostRoutine(Context->Context1, Context->Context2); + ExFreePoolWithTag(Context, 'CcDw'); + } + else + { + /* Otherwise, requeue it, but in tail, so that it doesn't block others + * This is clearly to improve, but given the poor algorithm used now + * It's better than nothing! + */ + ExInterlockedInsertTailList(&CcDeferredWrites, + &Context->CcDeferredWritesEntry, + &CcDeferredWriteSpinLock); + } + } } } @@ -1358,6 +1391,8 @@ CcInitView ( InitializeListHead(&DirtyVacbListHead); InitializeListHead(&VacbLruListHead); + InitializeListHead(&CcDeferredWrites); + KeInitializeSpinLock(&CcDeferredWriteSpinLock); KeInitializeGuardedMutex(&ViewLock); ExInitializeNPagedLookasideList(&iBcbLookasideList, NULL, diff --git a/ntoskrnl/include/internal/cc.h b/ntoskrnl/include/internal/cc.h index cc62381aad..05eb53fec7 100644 --- a/ntoskrnl/include/internal/cc.h +++ b/ntoskrnl/include/internal/cc.h @@ -41,6 +41,10 @@ // extern ULONG CcRosTraceLevel; extern LIST_ENTRY DirtyVacbListHead; +extern ULONG CcDirtyPageThreshold; +extern ULONG CcTotalDirtyPages; +extern LIST_ENTRY CcDeferredWrites; +extern KSPIN_LOCK CcDeferredWriteSpinLock; typedef struct _PF_SCENARIO_ID { @@ -193,6 +197,17 @@ typedef struct _ROS_VACB /* Pointer to the next VACB in a chain. */ } ROS_VACB, *PROS_VACB; +typedef struct _ROS_DEFERRED_WRITE_CONTEXT +{ + LIST_ENTRY CcDeferredWritesEntry; + PFILE_OBJECT FileObject; + PCC_POST_DEFERRED_WRITE PostRoutine; + PVOID Context1; + PVOID Context2; + ULONG BytesToWrite; + BOOLEAN Retrying; +} ROS_DEFERRED_WRITE_CONTEXT, *PROS_DEFERRED_WRITE_CONTEXT; + typedef struct _INTERNAL_BCB { /* Lock */
6 years, 11 months
1
0
0
0
02/05: [NTOSKRNL] When marking a BCB dirty, also mark the underlying VACB dirty. Experiment and MSDN tend to show that a dirty BCB is queued for lazy write. This will do the job here!
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=07e6e9c9c1415385edf7f…
commit 07e6e9c9c1415385edf7fb6ad5f503b88db8b047 Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Jan 23 21:48:29 2018 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Jan 23 23:25:26 2018 +0100 [NTOSKRNL] When marking a BCB dirty, also mark the underlying VACB dirty. Experiment and MSDN tend to show that a dirty BCB is queued for lazy write. This will do the job here! Also, renamed CcRosMarkDirtyFile() which is more accurate, and added a new function CcRosMarkDirtyVacb() which just takes a VACB as arg (expected locked) and marks it dirty (using previous implementation). Make CcRosMarkDirtyFile() use it. CORE-14235 --- ntoskrnl/cc/pin.c | 1 + ntoskrnl/cc/view.c | 42 ++++++++++++++++++++++++++++-------------- ntoskrnl/include/internal/cc.h | 7 ++++++- ntoskrnl/mm/section.c | 4 ++-- 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/ntoskrnl/cc/pin.c b/ntoskrnl/cc/pin.c index 0241927f95..393b206a0f 100644 --- a/ntoskrnl/cc/pin.c +++ b/ntoskrnl/cc/pin.c @@ -247,6 +247,7 @@ CcSetDirtyPinnedData ( Bcb, Lsn); iBcb->Dirty = TRUE; + CcRosMarkDirtyVacb(iBcb->Vacb); } diff --git a/ntoskrnl/cc/view.c b/ntoskrnl/cc/view.c index 0d1822c696..465fffa595 100644 --- a/ntoskrnl/cc/view.c +++ b/ntoskrnl/cc/view.c @@ -565,25 +565,15 @@ CcRosLookupVacb ( return NULL; } -NTSTATUS +VOID NTAPI CcRosMarkDirtyVacb ( - PROS_SHARED_CACHE_MAP SharedCacheMap, - LONGLONG FileOffset) + PROS_VACB Vacb) { - PROS_VACB Vacb; KIRQL oldIrql; + PROS_SHARED_CACHE_MAP SharedCacheMap; - ASSERT(SharedCacheMap); - - DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n", - SharedCacheMap, FileOffset); - - Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset); - if (Vacb == NULL) - { - KeBugCheck(CACHE_MANAGER); - } + SharedCacheMap = Vacb->SharedCacheMap; KeAcquireGuardedMutex(&ViewLock); KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); @@ -606,6 +596,30 @@ CcRosMarkDirtyVacb ( KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); KeReleaseGuardedMutex(&ViewLock); +} + +NTSTATUS +NTAPI +CcRosMarkDirtyFile ( + PROS_SHARED_CACHE_MAP SharedCacheMap, + LONGLONG FileOffset) +{ + PROS_VACB Vacb; + + ASSERT(SharedCacheMap); + + DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n", + SharedCacheMap, FileOffset); + + Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset); + if (Vacb == NULL) + { + KeBugCheck(CACHE_MANAGER); + } + + CcRosMarkDirtyVacb(Vacb); + + CcRosReleaseVacbLock(Vacb); return STATUS_SUCCESS; diff --git a/ntoskrnl/include/internal/cc.h b/ntoskrnl/include/internal/cc.h index b1bb1ab165..cc62381aad 100644 --- a/ntoskrnl/include/internal/cc.h +++ b/ntoskrnl/include/internal/cc.h @@ -281,11 +281,16 @@ CcInitCacheZeroPage(VOID); NTSTATUS NTAPI -CcRosMarkDirtyVacb( +CcRosMarkDirtyFile( PROS_SHARED_CACHE_MAP SharedCacheMap, LONGLONG FileOffset ); +VOID +NTAPI +CcRosMarkDirtyVacb( + PROS_VACB Vacb); + NTSTATUS NTAPI CcRosFlushDirtyPages( diff --git a/ntoskrnl/mm/section.c b/ntoskrnl/mm/section.c index 66fa6d2245..5c954395a9 100644 --- a/ntoskrnl/mm/section.c +++ b/ntoskrnl/mm/section.c @@ -2374,7 +2374,7 @@ MmWritePageSectionView(PMMSUPPORT AddressSpace, ASSERT(SwapEntry == 0); //SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset; #ifndef NEWCC - CcRosMarkDirtyVacb(SharedCacheMap, Offset.QuadPart); + CcRosMarkDirtyFile(SharedCacheMap, Offset.QuadPart); #endif MmLockSectionSegment(Segment); MmSetPageEntrySectionSegment(Segment, &Offset, PageEntry); @@ -4006,7 +4006,7 @@ MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, #ifndef NEWCC FileObject = MemoryArea->Data.SectionData.Section->FileObject; SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; - CcRosMarkDirtyVacb(SharedCacheMap, Offset.QuadPart + Segment->Image.FileOffset); + CcRosMarkDirtyFile(SharedCacheMap, Offset.QuadPart + Segment->Image.FileOffset); #endif ASSERT(SwapEntry == 0); }
6 years, 11 months
1
0
0
0
01/05: [NTOSKRNL] Bug fix: lazy write more often. CcDirtyPageThreshold is not here to compute when you have to write, but to know where you have to deny writes. More commits to come in that direction!
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6ba67b8152def148a87fd…
commit 6ba67b8152def148a87fdd6049e65956fb4656a9 Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Jan 23 21:36:19 2018 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Jan 23 23:25:26 2018 +0100 [NTOSKRNL] Bug fix: lazy write more often. CcDirtyPageThreshold is not here to compute when you have to write, but to know where you have to deny writes. More commits to come in that direction! CORE-14235 --- ntoskrnl/cc/view.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/ntoskrnl/cc/view.c b/ntoskrnl/cc/view.c index 8fb7f5333c..0d1822c696 100644 --- a/ntoskrnl/cc/view.c +++ b/ntoskrnl/cc/view.c @@ -326,23 +326,18 @@ CciLazyWriter(PVOID Unused) /* We're not sleeping anymore */ KeClearEvent(&iLazyWriterNotify); - /* Only start operations if above threshold */ - DPRINT("TS: %lu, Count: %lu\n", CcDirtyPageThreshold, CcTotalDirtyPages); - if (CcTotalDirtyPages > CcDirtyPageThreshold) + /* Our target is one-eighth of the dirty pages */ + Target = CcTotalDirtyPages / 8; + if (Target != 0) { - /* Our target is one-eighth of the dirty pages */ - Target = CcTotalDirtyPages / 8; - if (Target != 0) - { - /* Flush! */ - DPRINT("Lazy writer starting (%d)\n", Target); - CcRosFlushDirtyPages(Target, &Count, FALSE, TRUE); - - /* And update stats */ - CcLazyWritePages += Count; - ++CcLazyWriteIos; - DPRINT("Lazy writer done (%d)\n", Count); - } + /* Flush! */ + DPRINT("Lazy writer starting (%d)\n", Target); + CcRosFlushDirtyPages(Target, &Count, FALSE, TRUE); + + /* And update stats */ + CcLazyWritePages += Count; + ++CcLazyWriteIos; + DPRINT("Lazy writer done (%d)\n", Count); } /* Inform people waiting on us that we're done */
6 years, 11 months
1
0
0
0
01/01: [EXPLORER] Workaround for something that may or may not be an "unintended feature" of the comctl toolbar. Apparently the indices provided in NMTBGETINFOTIP (TBN_GETINFOTIP data struct), are not reliable, but since the lParam values are, and it saves us a lookup, we will be using those instead. Win-Win!
by David Quintana
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=5ec441a867dee5ffde551…
commit 5ec441a867dee5ffde551d40f71961baf7f671fd Author: David Quintana <gigaherz(a)gmail.com> AuthorDate: Tue Jan 23 23:10:44 2018 +0100 Commit: David Quintana <gigaherz(a)gmail.com> CommitDate: Tue Jan 23 23:10:44 2018 +0100 [EXPLORER] Workaround for something that may or may not be an "unintended feature" of the comctl toolbar. Apparently the indices provided in NMTBGETINFOTIP (TBN_GETINFOTIP data struct), are not reliable, but since the lParam values are, and it saves us a lookup, we will be using those instead. Win-Win! --- base/shell/explorer/trayntfy.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/base/shell/explorer/trayntfy.cpp b/base/shell/explorer/trayntfy.cpp index f61e1f6bb4..1b05b501a7 100644 --- a/base/shell/explorer/trayntfy.cpp +++ b/base/shell/explorer/trayntfy.cpp @@ -853,14 +853,17 @@ public: } - VOID GetTooltipText(int index, LPTSTR szTip, DWORD cchTip) + VOID GetTooltipText(LPARAM data, LPTSTR szTip, DWORD cchTip) { - InternalIconData * notifyItem = GetItemData(index); - + InternalIconData * notifyItem = reinterpret_cast<InternalIconData *>(data); if (notifyItem) { StringCchCopy(szTip, cchTip, notifyItem->szTip); } + else + { + StringCchCopy(szTip, cchTip, L""); + } } VOID ResizeImagelist() @@ -1240,7 +1243,7 @@ public: LRESULT OnGetInfoTip(INT uCode, LPNMHDR hdr, BOOL& bHandled) { NMTBGETINFOTIPW * nmtip = (NMTBGETINFOTIPW *) hdr; - Toolbar.GetTooltipText(nmtip->iItem, nmtip->pszText, nmtip->cchTextMax); + Toolbar.GetTooltipText(nmtip->lParam, nmtip->pszText, nmtip->cchTextMax); return TRUE; }
6 years, 11 months
1
0
0
0
02/02: [EXPLORER] Implement balloon queueing.
by David Quintana
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=bc43733e4842f4bcc5ea2…
commit bc43733e4842f4bcc5ea2d87fa9f69b442a3fcba Author: David Quintana <gigaherz(a)gmail.com> AuthorDate: Mon Jan 22 20:27:32 2018 +0100 Commit: David Quintana <gigaherz(a)gmail.com> CommitDate: Tue Jan 23 22:13:01 2018 +0100 [EXPLORER] Implement balloon queueing. --- base/shell/explorer/trayntfy.cpp | 313 ++++++++++++++++++++++++++++----------- 1 file changed, 226 insertions(+), 87 deletions(-) diff --git a/base/shell/explorer/trayntfy.cpp b/base/shell/explorer/trayntfy.cpp index 7e13d9f131..f61e1f6bb4 100644 --- a/base/shell/explorer/trayntfy.cpp +++ b/base/shell/explorer/trayntfy.cpp @@ -40,7 +40,6 @@ struct InternalIconData : NOTIFYICONDATA UINT uVersionCopy; }; - struct IconWatcherData { HANDLE hProcess; @@ -314,6 +313,203 @@ private: } }; +class CBalloonQueue +{ +public: + static const int TimerInterval = 2000; + static const int BalloonsTimerId = 1; + static const int MinTimeout = 10000; + static const int MaxTimeout = 30000; + static const int CooldownBetweenBalloons = 2000; + +private: + struct Info + { + InternalIconData * pSource; + WCHAR szInfo[256]; + WCHAR szInfoTitle[64]; + WPARAM uIcon; + UINT uTimeout; + + Info(InternalIconData * source) + { + pSource = source; + StrNCpy(szInfo, source->szInfo, _countof(szInfo)); + StrNCpy(szInfoTitle, source->szInfoTitle, _countof(szInfoTitle)); + uIcon = source->dwInfoFlags & NIIF_ICON_MASK; + if (source->dwInfoFlags == NIIF_USER) + uIcon = reinterpret_cast<WPARAM>(source->hIcon); + uTimeout = source->uTimeout; + } + }; + + HWND m_hwndParent; + + CTooltips * m_tooltips; + + CAtlList<Info> m_queue; + + CToolbar<InternalIconData> * m_toolbar; + + InternalIconData * m_current; + bool m_currentClosed; + + int m_timer; + +public: + CBalloonQueue() : + m_hwndParent(NULL), + m_tooltips(NULL), + m_toolbar(NULL), + m_current(NULL), + m_currentClosed(false), + m_timer(-1) + { + } + + void Init(HWND hwndParent, CToolbar<InternalIconData> * toolbar, CTooltips * balloons) + { + m_hwndParent = hwndParent; + m_toolbar = toolbar; + m_tooltips = balloons; + } + + void Deinit() + { + if (m_timer >= 0) + { + ::KillTimer(m_hwndParent, m_timer); + } + } + + bool OnTimer(int timerId) + { + if (timerId != m_timer) + return false; + + ::KillTimer(m_hwndParent, m_timer); + m_timer = -1; + + if (m_current && !m_currentClosed) + { + Close(m_current); + } + else + { + m_current = NULL; + m_currentClosed = false; + if (!m_queue.IsEmpty()) + { + Info info = m_queue.RemoveHead(); + Show(info); + } + } + + return true; + } + + void UpdateInfo(InternalIconData * notifyItem) + { + size_t len = 0; + HRESULT hr = StringCchLength(notifyItem->szInfo, _countof(notifyItem->szInfo), &len); + if (SUCCEEDED(hr) && len > 0) + { + Info info(notifyItem); + + // If m_current == notifyItem, we want to replace the previous balloon even if there is a queue. + if (m_current != notifyItem && (m_current != NULL || !m_queue.IsEmpty())) + { + m_queue.AddTail(info); + } + else + { + Show(info); + } + } + else + { + Close(notifyItem); + } + } + + void RemoveInfo(InternalIconData * notifyItem) + { + Close(notifyItem); + + POSITION position = m_queue.GetHeadPosition(); + while(position != NULL) + { + Info& info = m_queue.GetNext(position); + if (info.pSource == notifyItem) + { + m_queue.RemoveAt(position); + } + } + } + + void CloseCurrent() + { + if (m_current != NULL) + Close(m_current); + } + +private: + + int IndexOf(InternalIconData * pdata) + { + int count = m_toolbar->GetButtonCount(); + for (int i = 0; i < count; i++) + { + if (m_toolbar->GetItemData(i) == pdata) + return i; + } + return -1; + } + + void SetTimer(int length) + { + m_timer = ::SetTimer(m_hwndParent, BalloonsTimerId, length, NULL); + } + + void Show(Info& info) + { + TRACE("ShowBalloonTip called for flags=%x text=%ws; title=%ws\n", info.uIcon, info.szInfo, info.szInfoTitle); + + // TODO: NIF_REALTIME, NIIF_NOSOUND, other Vista+ flags + + const int index = IndexOf(info.pSource); + RECT rc; + m_toolbar->GetItemRect(index, &rc); + m_toolbar->ClientToScreen(&rc); + const WORD x = (rc.left + rc.right) / 2; + const WORD y = (rc.top + rc.bottom) / 2; + + m_tooltips->SetTitle(info.szInfoTitle, info.uIcon); + m_tooltips->TrackPosition(x, y); + m_tooltips->UpdateTipText(m_hwndParent, reinterpret_cast<LPARAM>(m_toolbar->m_hWnd), info.szInfo); + m_tooltips->TrackActivate(m_hwndParent, reinterpret_cast<LPARAM>(m_toolbar->m_hWnd)); + + m_current = info.pSource; + int timeout = info.uTimeout; + if (timeout < MinTimeout) timeout = MinTimeout; + if (timeout > MaxTimeout) timeout = MaxTimeout; + + SetTimer(timeout); + } + + void Close(IN OUT InternalIconData * notifyItem) + { + TRACE("HideBalloonTip called\n"); + + if (m_current == notifyItem && !m_currentClosed) + { + // Prevent Re-entry + m_currentClosed = true; + m_tooltips->TrackDeactivate(); + SetTimer(CooldownBetweenBalloons); + } + } +}; class CNotifyToolbar : public CWindowImplBaseT< CToolbar<InternalIconData>, CControlWinTraits > @@ -321,17 +517,13 @@ class CNotifyToolbar : HIMAGELIST m_ImageList; int m_VisibleButtonCount; - HWND m_BalloonsParent; - CTooltips * m_Balloons; - InternalIconData * m_currentTooltip; + CBalloonQueue * m_BalloonQueue; public: CNotifyToolbar() : m_ImageList(NULL), m_VisibleButtonCount(0), - m_BalloonsParent(NULL), - m_Balloons(NULL), - m_currentTooltip(NULL) + m_BalloonQueue(NULL) { } @@ -455,14 +647,15 @@ public: StrNCpy(notifyItem->szInfoTitle, iconData->szInfoTitle, _countof(notifyItem->szInfo)); notifyItem->dwInfoFlags = iconData->dwInfoFlags; notifyItem->uTimeout = iconData->uTimeout; - } - m_VisibleButtonCount++; if (notifyItem->dwState & NIS_HIDDEN) { tbBtn.fsState |= TBSTATE_HIDDEN; - m_VisibleButtonCount--; + } + else + { + m_VisibleButtonCount++; } /* TODO: support VERSION_4 (NIF_GUID, NIF_REALTIME, NIF_SHOWTIP) */ @@ -472,7 +665,7 @@ public: if (iconData->uFlags & NIF_INFO) { - UpdateBalloonTip(notifyItem); + m_BalloonQueue->UpdateInfo(notifyItem); } return TRUE; @@ -600,7 +793,7 @@ public: if (iconData->uFlags & NIF_INFO) { - UpdateBalloonTip(notifyItem); + m_BalloonQueue->UpdateInfo(notifyItem); } return TRUE; @@ -650,7 +843,7 @@ public: } } - HideBalloonTip(notifyItem); + m_BalloonQueue->RemoveInfo(notifyItem); DeleteButton(index); @@ -659,73 +852,6 @@ public: return TRUE; } - void UpdateBalloonTip(InternalIconData* notifyItem) - { - size_t len = 0; - if (SUCCEEDED(StringCchLength(notifyItem->szInfo, _countof(notifyItem->szInfo), &len)) && len > 0) - { - ShowBalloonTip(notifyItem); - } - else - { - HideBalloonTip(notifyItem); - } - } - - static WPARAM GetTitleIcon(DWORD dwFlags, HICON hIcon) - { - if (dwFlags & NIIF_USER) - return reinterpret_cast<WPARAM>(hIcon); - - return dwFlags & 3; - } - - BOOL ShowBalloonTip(IN OUT InternalIconData *notifyItem) - { - DbgPrint("ShowBalloonTip called for flags=%x text=%ws; title=%ws", notifyItem->dwInfoFlags, notifyItem->szInfo, notifyItem->szInfoTitle); - - // TODO: Queueing -> NIF_REALTIME? (Vista+) - // TODO: NIIF_NOSOUND, Vista+ flags - - const WPARAM icon = GetTitleIcon(notifyItem->dwInfoFlags, notifyItem->hIcon); - BOOL ret = m_Balloons->SetTitle(notifyItem->szInfoTitle, icon); - if (!ret) - DbgPrint("SetTitle failed, GetLastError=%d", GetLastError()); - - const int index = FindItem(notifyItem->hWnd, notifyItem->uID, NULL); - RECT rc; - GetItemRect(index, &rc); - ClientToScreen(&rc); // I have no idea why this is needed! >_< - WORD x = (rc.left + rc.right) / 2; - WORD y = (rc.top + rc.bottom) / 2; - DbgPrint("ClientToScreen returned (%d, %d, %d, %d) x=%d, y=%d", - rc.left, rc.top, - rc.right, rc.bottom, x, y); - m_Balloons->TrackPosition(x, y); - m_Balloons->UpdateTipText(m_BalloonsParent, reinterpret_cast<LPARAM>(m_hWnd), notifyItem->szInfo); - m_Balloons->TrackActivate(m_BalloonsParent, reinterpret_cast<LPARAM>(m_hWnd)); - m_currentTooltip = notifyItem; - - return TRUE; - } - - VOID HideBalloonTip(IN OUT InternalIconData *notifyItem) - { - DbgPrint("HideBalloonTip called"); - - if (m_currentTooltip == notifyItem) - { - // Prevent Re-entry - m_currentTooltip = NULL; - m_Balloons->TrackDeactivate(); - } - } - - VOID HideCurrentBalloon() - { - if (m_currentTooltip != NULL) - HideBalloonTip(m_currentTooltip); - } VOID GetTooltipText(int index, LPTSTR szTip, DWORD cchTip) { @@ -909,10 +1035,9 @@ public: NOTIFY_CODE_HANDLER(TTN_SHOW, OnTooltipShow) END_MSG_MAP() - void Initialize(HWND hWndParent, CTooltips * tooltips) + void Initialize(HWND hWndParent, CBalloonQueue * queue) { - m_BalloonsParent = hWndParent; - m_Balloons = tooltips; + m_BalloonQueue = queue; DWORD styles = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | @@ -951,8 +1076,8 @@ class CSysPagerWnd : public CIconWatcher { CNotifyToolbar Toolbar; - CTooltips m_Balloons; + CBalloonQueue m_BalloonQueue; public: CSysPagerWnd() {} @@ -983,7 +1108,7 @@ public: LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { - Toolbar.Initialize(m_hWnd, &m_Balloons); + Toolbar.Initialize(m_hWnd, &m_BalloonQueue); CIconWatcher::Initialize(m_hWnd); HWND hWndTop = GetAncestor(m_hWnd, GA_ROOT); @@ -1001,9 +1126,11 @@ public: BOOL ret = m_Balloons.AddTool(&ti); if (!ret) { - DbgPrint("AddTool failed, LastError=%d (probably meaningless unless non-zero)", GetLastError()); + WARN("AddTool failed, LastError=%d (probably meaningless unless non-zero)\n", GetLastError()); } + m_BalloonQueue.Init(m_hWnd, &Toolbar, &m_Balloons); + // Explicitly request running applications to re-register their systray icons ::SendNotifyMessageW(HWND_BROADCAST, RegisterWindowMessageW(L"TaskbarCreated"), @@ -1014,6 +1141,7 @@ public: LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { + m_BalloonQueue.Deinit(); CIconWatcher::Uninitialize(); return TRUE; } @@ -1165,11 +1293,21 @@ public: LRESULT OnBalloonPop(UINT uCode, LPNMHDR hdr , BOOL& bHandled) { - Toolbar.HideCurrentBalloon(); + m_BalloonQueue.CloseCurrent(); bHandled = TRUE; return 0; } + LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if (m_BalloonQueue.OnTimer(wParam)) + { + bHandled = TRUE; + } + + return 0; + } + void ResizeImagelist() { Toolbar.ResizeImagelist(); @@ -1183,6 +1321,7 @@ public: MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu) + MESSAGE_HANDLER(WM_TIMER, OnTimer) NOTIFY_CODE_HANDLER(TTN_POP, OnBalloonPop) NOTIFY_CODE_HANDLER(TBN_GETINFOTIPW, OnGetInfoTip) NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
6 years, 11 months
1
0
0
0
01/02: [EXPLORER] Implement rudimentary uVersion management, and notification balloons. - uVersion will only be truly useful when Vista+'s V4 style notification icons are implemented. - Balloon notifications do not yet support queuing and auto-closing. - Force the notification icon tooltips to always show even if the taskbar isn't foreground. [ROSCTRLS.H] Implement CTooltips class which manages a comctl32 tooltips window.
by David Quintana
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=bbca71c4a5604f4919d79…
commit bbca71c4a5604f4919d792c4b414ae84a05c4594 Author: David Quintana <gigaherz(a)gmail.com> AuthorDate: Fri Jan 19 16:39:46 2018 +0100 Commit: David Quintana <gigaherz(a)gmail.com> CommitDate: Tue Jan 23 22:13:01 2018 +0100 [EXPLORER] Implement rudimentary uVersion management, and notification balloons. - uVersion will only be truly useful when Vista+'s V4 style notification icons are implemented. - Balloon notifications do not yet support queuing and auto-closing. - Force the notification icon tooltips to always show even if the taskbar isn't foreground. [ROSCTRLS.H] Implement CTooltips class which manages a comctl32 tooltips window. --- base/shell/explorer/trayntfy.cpp | 217 +++++++++++++++++++++++++++++++++---- sdk/include/reactos/rosctrls.h | 225 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 421 insertions(+), 21 deletions(-) diff --git a/base/shell/explorer/trayntfy.cpp b/base/shell/explorer/trayntfy.cpp index 1864e33e96..7e13d9f131 100644 --- a/base/shell/explorer/trayntfy.cpp +++ b/base/shell/explorer/trayntfy.cpp @@ -34,6 +34,12 @@ typedef struct _SYS_PAGER_COPY_DATA NOTIFYICONDATA nicon_data; } SYS_PAGER_COPY_DATA, *PSYS_PAGER_COPY_DATA; +struct InternalIconData : NOTIFYICONDATA +{ + // Must keep a separate copy since the original is unioned with uTimeout. + UINT uVersionCopy; +}; + struct IconWatcherData { @@ -310,15 +316,22 @@ private: class CNotifyToolbar : - public CWindowImplBaseT< CToolbar<NOTIFYICONDATA>, CControlWinTraits > + public CWindowImplBaseT< CToolbar<InternalIconData>, CControlWinTraits > { HIMAGELIST m_ImageList; int m_VisibleButtonCount; + HWND m_BalloonsParent; + CTooltips * m_Balloons; + InternalIconData * m_currentTooltip; + public: CNotifyToolbar() : m_ImageList(NULL), - m_VisibleButtonCount(0) + m_VisibleButtonCount(0), + m_BalloonsParent(NULL), + m_Balloons(NULL), + m_currentTooltip(NULL) { } @@ -331,15 +344,13 @@ public: return m_VisibleButtonCount; } - int FindItem(IN HWND hWnd, IN UINT uID, NOTIFYICONDATA ** pdata) + int FindItem(IN HWND hWnd, IN UINT uID, InternalIconData ** pdata) { int count = GetButtonCount(); for (int i = 0; i < count; i++) { - NOTIFYICONDATA * data; - - data = GetItemData(i); + InternalIconData * data = GetItemData(i); if (data->hWnd == hWnd && data->uID == uID) @@ -358,7 +369,7 @@ public: int count = GetButtonCount(); for (int i = 0; i < count; i++) { - NOTIFYICONDATA * data = GetItemData(i); + InternalIconData * data = GetItemData(i); if (data->hIcon == handle) { TBBUTTON btn; @@ -373,7 +384,7 @@ public: BOOL AddButton(IN CONST NOTIFYICONDATA *iconData) { TBBUTTON tbBtn; - NOTIFYICONDATA * notifyItem; + InternalIconData * notifyItem; WCHAR text[] = L""; TRACE("Adding icon %d from hWnd %08x flags%s%s state%s%s", @@ -390,7 +401,7 @@ public: return FALSE; } - notifyItem = new NOTIFYICONDATA(); + notifyItem = new InternalIconData(); ZeroMemory(notifyItem, sizeof(*notifyItem)); notifyItem->hWnd = iconData->hWnd; @@ -437,6 +448,16 @@ public: StringCchCopy(notifyItem->szTip, _countof(notifyItem->szTip), iconData->szTip); } + if (iconData->uFlags & NIF_INFO) + { + // NOTE: In Vista+, the uTimeout value is disregarded, and the accessibility settings are used always. + StrNCpy(notifyItem->szInfo, iconData->szInfo, _countof(notifyItem->szInfo)); + StrNCpy(notifyItem->szInfoTitle, iconData->szInfoTitle, _countof(notifyItem->szInfo)); + notifyItem->dwInfoFlags = iconData->dwInfoFlags; + notifyItem->uTimeout = iconData->uTimeout; + + } + m_VisibleButtonCount++; if (notifyItem->dwState & NIS_HIDDEN) { @@ -444,17 +465,45 @@ public: m_VisibleButtonCount--; } - /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */ + /* TODO: support VERSION_4 (NIF_GUID, NIF_REALTIME, NIF_SHOWTIP) */ CToolbar::AddButton(&tbBtn); SetButtonSize(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); + if (iconData->uFlags & NIF_INFO) + { + UpdateBalloonTip(notifyItem); + } + + return TRUE; + } + + BOOL SwitchVersion(IN CONST NOTIFYICONDATA *iconData) + { + InternalIconData * notifyItem; + int index = FindItem(iconData->hWnd, iconData->uID, ¬ifyItem); + if (index < 0) + { + WARN("Icon %d from hWnd %08x DOES NOT EXIST!", iconData->uID, iconData->hWnd); + return FALSE; + } + + if (iconData->uVersion != 0 && iconData->uVersion != NOTIFYICON_VERSION) + { + WARN("Tried to set the version of icon %d from hWnd %08x, to an unknown value %d. Vista+ program?", iconData->uID, iconData->hWnd, iconData->uVersion); + return FALSE; + } + + // We can not store the version in the uVersion field, because it's union'd with uTimeout, + // which we also need to keep track of. + notifyItem->uVersionCopy = iconData->uVersion; + return TRUE; } BOOL UpdateButton(IN CONST NOTIFYICONDATA *iconData) { - NOTIFYICONDATA * notifyItem; + InternalIconData * notifyItem; TBBUTTONINFO tbbi = { 0 }; TRACE("Updating icon %d from hWnd %08x flags%s%s state%s%s", @@ -536,16 +585,30 @@ public: StringCchCopy(notifyItem->szTip, _countof(notifyItem->szTip), iconData->szTip); } - /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */ + if (iconData->uFlags & NIF_INFO) + { + // NOTE: In Vista+, the uTimeout value is disregarded, and the accessibility settings are used always. + StrNCpy(notifyItem->szInfo, iconData->szInfo, _countof(notifyItem->szInfo)); + StrNCpy(notifyItem->szInfoTitle, iconData->szInfoTitle, _countof(notifyItem->szInfo)); + notifyItem->dwInfoFlags = iconData->dwInfoFlags; + notifyItem->uTimeout = iconData->uTimeout; + } + + /* TODO: support VERSION_4 (NIF_GUID, NIF_REALTIME, NIF_SHOWTIP) */ SetButtonInfo(index, &tbbi); + if (iconData->uFlags & NIF_INFO) + { + UpdateBalloonTip(notifyItem); + } + return TRUE; } BOOL RemoveButton(IN CONST NOTIFYICONDATA *iconData) { - NOTIFYICONDATA * notifyItem; + InternalIconData * notifyItem; TRACE("Removing icon %d from hWnd %08x", iconData->uID, iconData->hWnd); @@ -587,16 +650,86 @@ public: } } - delete notifyItem; + HideBalloonTip(notifyItem); + DeleteButton(index); + delete notifyItem; + return TRUE; } + void UpdateBalloonTip(InternalIconData* notifyItem) + { + size_t len = 0; + if (SUCCEEDED(StringCchLength(notifyItem->szInfo, _countof(notifyItem->szInfo), &len)) && len > 0) + { + ShowBalloonTip(notifyItem); + } + else + { + HideBalloonTip(notifyItem); + } + } + + static WPARAM GetTitleIcon(DWORD dwFlags, HICON hIcon) + { + if (dwFlags & NIIF_USER) + return reinterpret_cast<WPARAM>(hIcon); + + return dwFlags & 3; + } + + BOOL ShowBalloonTip(IN OUT InternalIconData *notifyItem) + { + DbgPrint("ShowBalloonTip called for flags=%x text=%ws; title=%ws", notifyItem->dwInfoFlags, notifyItem->szInfo, notifyItem->szInfoTitle); + + // TODO: Queueing -> NIF_REALTIME? (Vista+) + // TODO: NIIF_NOSOUND, Vista+ flags + + const WPARAM icon = GetTitleIcon(notifyItem->dwInfoFlags, notifyItem->hIcon); + BOOL ret = m_Balloons->SetTitle(notifyItem->szInfoTitle, icon); + if (!ret) + DbgPrint("SetTitle failed, GetLastError=%d", GetLastError()); + + const int index = FindItem(notifyItem->hWnd, notifyItem->uID, NULL); + RECT rc; + GetItemRect(index, &rc); + ClientToScreen(&rc); // I have no idea why this is needed! >_< + WORD x = (rc.left + rc.right) / 2; + WORD y = (rc.top + rc.bottom) / 2; + DbgPrint("ClientToScreen returned (%d, %d, %d, %d) x=%d, y=%d", + rc.left, rc.top, + rc.right, rc.bottom, x, y); + m_Balloons->TrackPosition(x, y); + m_Balloons->UpdateTipText(m_BalloonsParent, reinterpret_cast<LPARAM>(m_hWnd), notifyItem->szInfo); + m_Balloons->TrackActivate(m_BalloonsParent, reinterpret_cast<LPARAM>(m_hWnd)); + m_currentTooltip = notifyItem; + + return TRUE; + } + + VOID HideBalloonTip(IN OUT InternalIconData *notifyItem) + { + DbgPrint("HideBalloonTip called"); + + if (m_currentTooltip == notifyItem) + { + // Prevent Re-entry + m_currentTooltip = NULL; + m_Balloons->TrackDeactivate(); + } + } + + VOID HideCurrentBalloon() + { + if (m_currentTooltip != NULL) + HideBalloonTip(m_currentTooltip); + } + VOID GetTooltipText(int index, LPTSTR szTip, DWORD cchTip) { - NOTIFYICONDATA * notifyItem; - notifyItem = GetItemData(index); + InternalIconData * notifyItem = GetItemData(index); if (notifyItem) { @@ -626,7 +759,7 @@ public: int count = GetButtonCount(); for (int i = 0; i < count; i++) { - NOTIFYICONDATA * data = GetItemData(i); + InternalIconData * data = GetItemData(i); BOOL hasSharedIcon = data->dwState & NIS_SHAREDICON; INT iIcon = hasSharedIcon ? FindExistingSharedIcon(data->hIcon) : -1; if (iIcon < 0) @@ -659,7 +792,7 @@ private: L"WM_XBUTTONDBLCLK" }; - NOTIFYICONDATA * notifyItem = GetItemData(wIndex); + InternalIconData * notifyItem = GetItemData(wIndex); if (!::IsWindow(notifyItem->hWnd)) { @@ -770,15 +903,17 @@ private: return 0; } - public: BEGIN_MSG_MAP(CNotifyToolbar) MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseEvent) NOTIFY_CODE_HANDLER(TTN_SHOW, OnTooltipShow) END_MSG_MAP() - void Initialize(HWND hWndParent) + void Initialize(HWND hWndParent, CTooltips * tooltips) { + m_BalloonsParent = hWndParent; + m_Balloons = tooltips; + DWORD styles = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_TRANSPARENT | @@ -786,6 +921,13 @@ public: SubclassWindow(CToolbar::Create(hWndParent, styles)); + // Force the toolbar tooltips window to always show tooltips even if not foreground + HWND tooltipsWnd = (HWND)SendMessageW(TB_GETTOOLTIPS); + if (tooltipsWnd) + { + ::SetWindowLong(tooltipsWnd, GWL_STYLE, ::GetWindowLong(tooltipsWnd, GWL_STYLE) | TTS_ALWAYSTIP); + } + SetWindowTheme(m_hWnd, L"TrayNotify", NULL); m_ImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 0, 1000); @@ -810,6 +952,8 @@ class CSysPagerWnd : { CNotifyToolbar Toolbar; + CTooltips m_Balloons; + public: CSysPagerWnd() {} virtual ~CSysPagerWnd() {} @@ -839,9 +983,27 @@ public: LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { - Toolbar.Initialize(m_hWnd); + Toolbar.Initialize(m_hWnd, &m_Balloons); CIconWatcher::Initialize(m_hWnd); + HWND hWndTop = GetAncestor(m_hWnd, GA_ROOT); + + m_Balloons.Create(hWndTop, TTS_NOPREFIX | TTS_BALLOON | TTS_CLOSE); + + TOOLINFOW ti = { 0 }; + ti.cbSize = TTTOOLINFOW_V1_SIZE; + ti.uFlags = TTF_TRACK | TTF_IDISHWND; + ti.uId = reinterpret_cast<UINT_PTR>(Toolbar.m_hWnd); + ti.hwnd = m_hWnd; + ti.lpszText = NULL; + ti.lParam = NULL; + + BOOL ret = m_Balloons.AddTool(&ti); + if (!ret) + { + DbgPrint("AddTool failed, LastError=%d (probably meaningless unless non-zero)", GetLastError()); + } + // Explicitly request running applications to re-register their systray icons ::SendNotifyMessageW(HWND_BROADCAST, RegisterWindowMessageW(L"TaskbarCreated"), @@ -890,6 +1052,11 @@ public: (void)RemoveIconFromWatcher(iconData); } break; + case NIM_SETFOCUS: + Toolbar.SetFocus(); + ret = TRUE; + case NIM_SETVERSION: + ret = Toolbar.SwitchVersion(iconData); default: TRACE("NotifyIconCmd received with unknown code %d.\n", data->notify_code); return FALSE; @@ -996,6 +1163,13 @@ public: return 0; } + LRESULT OnBalloonPop(UINT uCode, LPNMHDR hdr , BOOL& bHandled) + { + Toolbar.HideCurrentBalloon(); + bHandled = TRUE; + return 0; + } + void ResizeImagelist() { Toolbar.ResizeImagelist(); @@ -1009,6 +1183,7 @@ public: MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu) + NOTIFY_CODE_HANDLER(TTN_POP, OnBalloonPop) NOTIFY_CODE_HANDLER(TBN_GETINFOTIPW, OnGetInfoTip) NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw) END_MSG_MAP() diff --git a/sdk/include/reactos/rosctrls.h b/sdk/include/reactos/rosctrls.h index a5976416d8..f332aca915 100644 --- a/sdk/include/reactos/rosctrls.h +++ b/sdk/include/reactos/rosctrls.h @@ -581,3 +581,228 @@ public: } }; + +class CTooltips : + public CWindow +{ +public: // Configuration methods + + HWND Create(HWND hWndParent, DWORD dwStyles = WS_POPUP | TTS_NOPREFIX, DWORD dwExStyles = WS_EX_TOPMOST) + { + RECT r = { 0 }; + return CWindow::Create(TOOLTIPS_CLASS, hWndParent, r, L"", dwStyles, dwExStyles); + } + +public: // Relay event + + // Win7+: Can use GetMessageExtraInfo to provide the WPARAM value. + VOID RelayEvent(MSG * pMsg, WPARAM extraInfo = 0) + { + SendMessageW(TTM_RELAYEVENT, extraInfo, reinterpret_cast<LPARAM>(pMsg)); + } + +public: // Helpers + + INT GetToolCount() + { + return SendMessageW(TTM_GETTOOLCOUNT, 0, 0); + } + + BOOL AddTool(IN CONST TTTOOLINFOW * pInfo) + { + return SendMessageW(TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(pInfo)); + } + + VOID DelTool(IN HWND hwndToolOwner, IN UINT uId) + { + TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 }; + info.hwnd = hwndToolOwner; + info.uId = uId; + SendMessageW(TTM_DELTOOL, 0, reinterpret_cast<LPARAM>(&info)); + } + + VOID NewToolRect(IN HWND hwndToolOwner, IN UINT uId, IN RECT rect) + { + TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 }; + info.hwnd = hwndToolOwner; + info.uId = uId; + info.rect = rect; + SendMessageW(TTM_NEWTOOLRECT, 0, reinterpret_cast<LPARAM>(&info)); + } + + BOOL GetToolInfo(IN HWND hwndToolOwner, IN UINT uId, IN OUT TTTOOLINFOW * pInfo) + { + pInfo->hwnd = hwndToolOwner; + pInfo->uId = uId; + return SendMessageW(TTM_GETTOOLINFO, 0, reinterpret_cast<LPARAM>(pInfo)); + } + + VOID SetToolInfo(IN CONST TTTOOLINFOW * pInfo) + { + SendMessageW(TTM_SETTOOLINFO, 0, reinterpret_cast<LPARAM>(pInfo)); + } + + BOOL HitTest(IN CONST TTHITTESTINFOW * pInfo) + { + return SendMessageW(TTM_HITTEST, 0, reinterpret_cast<LPARAM>(pInfo)); + } + + VOID GetText(IN HWND hwndToolOwner, IN UINT uId, OUT PWSTR pBuffer, IN DWORD cchBuffer) + { + TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 }; + info.hwnd = hwndToolOwner; + info.uId = uId; + info.lpszText = pBuffer; + SendMessageW(TTM_GETTEXT, cchBuffer, reinterpret_cast<LPARAM>(&info)); + } + + VOID UpdateTipText(IN HWND hwndToolOwner, IN UINT uId, IN PCWSTR szText, IN HINSTANCE hinstResourceOwner = NULL) + { + TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 }; + info.hwnd = hwndToolOwner; + info.uId = uId; + info.lpszText = const_cast<PWSTR>(szText); + info.hinst = hinstResourceOwner; + SendMessageW(TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info)); + } + + BOOL EnumTools(IN CONST TTTOOLINFOW * pInfo) + { + return SendMessageW(TTM_ENUMTOOLS, 0, reinterpret_cast<LPARAM>(pInfo)); + } + + BOOL GetCurrentTool(OUT OPTIONAL TTTOOLINFOW * pInfo = NULL) + { + return SendMessageW(TTM_GETCURRENTTOOL, 0, reinterpret_cast<LPARAM>(pInfo)); + } + + VOID GetTitle(TTGETTITLE * pTitleInfo) + { + SendMessageW(TTM_GETTITLE, 0, reinterpret_cast<LPARAM>(pTitleInfo)); + } + + BOOL SetTitle(PCWSTR szTitleText, WPARAM icon = 0) + { + return SendMessageW(TTM_SETTITLE, icon, reinterpret_cast<LPARAM>(szTitleText)); + } + + VOID TrackActivate(IN HWND hwndToolOwner, IN UINT uId) + { + TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 }; + info.hwnd = hwndToolOwner; + info.uId = uId; + SendMessageW(TTM_TRACKACTIVATE, TRUE, reinterpret_cast<LPARAM>(&info)); + } + + VOID TrackDeactivate() + { + SendMessageW(TTM_TRACKACTIVATE, FALSE, NULL); + } + + VOID TrackPosition(IN WORD x, IN WORD y) + { + SendMessageW(TTM_TRACKPOSITION, 0, MAKELPARAM(x, y)); + } + + // Opens the tooltip + VOID Popup() + { + SendMessageW(TTM_POPUP); + } + + // Closes the tooltip - Pressing the [X] for a TTF_CLOSE balloon is equivalent to calling this + VOID Pop() + { + SendMessageW(TTM_POP); + } + + // Delay times for AUTOMATIC tooltips (they don't affect balloons) + INT GetDelayTime(UINT which) + { + return SendMessageW(TTM_GETDELAYTIME, which); + } + + VOID SetDelayTime(UINT which, WORD time) + { + SendMessageW(TTM_SETDELAYTIME, which, MAKELPARAM(time, 0)); + } + + // Activates or deactivates the automatic tooltip display when hovering a control + VOID Activate(IN BOOL bActivate = TRUE) + { + SendMessageW(TTM_ACTIVATE, bActivate); + } + + // Adjusts the position of a tooltip when used to display trimmed text + VOID AdjustRect(IN BOOL bTextToWindow, IN OUT RECT * pRect) + { + SendMessageW(TTM_ADJUSTRECT, bTextToWindow, reinterpret_cast<LPARAM>(pRect)); + } + + // Useful for TTF_ABSOLUTE|TTF_TRACK tooltip positioning + SIZE GetBubbleSize(IN TTTOOLINFOW * pInfo) + { + DWORD ret = SendMessageW(TTM_GETBUBBLESIZE, 0, reinterpret_cast<LPARAM>(pInfo)); + const SIZE sz = { LOWORD(ret), HIWORD(ret) }; + return sz; + } + + // Fills the RECT with the margin size previously set. Default is 0 margins. + VOID GetMargin(OUT RECT * pRect) + { + SendMessageW(TTM_GETMARGIN, 0, reinterpret_cast<LPARAM>(pRect)); + } + + VOID SetMargin(IN RECT * pRect) + { + SendMessageW(TTM_SETMARGIN, 0, reinterpret_cast<LPARAM>(pRect)); + } + + // Gets a previously established max width. Returns -1 if no limit is set + INT GetMaxTipWidth() + { + return SendMessageW(TTM_GETMAXTIPWIDTH); + } + + INT SetMaxTipWidth(IN OPTIONAL INT width = -1) + { + return SendMessageW(TTM_SETMAXTIPWIDTH, 0, width); + } + + // Get the color of the tooltip text + COLORREF GetTipTextColor() + { + return SendMessageW(TTM_GETTIPTEXTCOLOR); + } + + VOID SetTipTextColor(IN COLORREF textColor) + { + SendMessageW(TTM_SETTIPTEXTCOLOR, textColor); + } + + COLORREF GetTipBkColor() + { + return SendMessageW(TTM_GETTIPBKCOLOR); + } + + VOID SetTipBkColor(IN COLORREF textColor) + { + SendMessageW(TTM_SETTIPBKCOLOR, textColor); + } + + VOID SetWindowTheme(IN PCWSTR szThemeName) + { + SendMessageW(TTM_SETWINDOWTHEME, 0, reinterpret_cast<LPARAM>(szThemeName)); + } + + // Forces redraw + VOID Update() + { + SendMessageW(TTM_UPDATE); + } + + HWND WindowFromPoint(IN POINT * pPoint) + { + return reinterpret_cast<HWND>(SendMessageW(TTM_WINDOWFROMPOINT, 0, reinterpret_cast<LPARAM>(pPoint))); + } +};
6 years, 11 months
1
0
0
0
01/01: [NTOSKRNL] Reimplement the lazy writer in Cc and remove the "basic" one in Mm. This removes the "modified page writer" thread in Mm that was regularly blindly attempting to flush dirty pages to the disk. Instead, this commit introduces a lazy writer that will monitor dirty pages count and will flush them to disk when this count is above a threshold. The threshold is computed on Cc init. Compared to what was done previously, this lazy writer will only write down files that are not marked a
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c7ad200f8bc1b40c6ed94…
commit c7ad200f8bc1b40c6ed942176eb43d0a04bfaf8a Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Jan 23 19:07:25 2018 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Jan 23 19:33:59 2018 +0100 [NTOSKRNL] Reimplement the lazy writer in Cc and remove the "basic" one in Mm. This removes the "modified page writer" thread in Mm that was regularly blindly attempting to flush dirty pages to the disk. Instead, this commit introduces a lazy writer that will monitor dirty pages count and will flush them to disk when this count is above a threshold. The threshold is computed on Cc init. Compared to what was done previously, this lazy writer will only write down files that are not marked as temporary. The mechanisms involved in this lazy writer worker are well described in Windows Internals 4th editions (constants are coming from it ;-)). Also fixed a bad (and old!) bug in CcRosFlushDirtyPages() where target count could be overflow and the function would spin forever while holding the VACBs lock. This is mandatory as now lazy writer will call it with "random" values. This also allows implementing CcWaitForCurrentLazyWriterActivity() :-). Also renamed DirtyPageCount to its MS equivalent. CORE-14235 --- ntoskrnl/cache/newcc.h | 2 +- ntoskrnl/cc/cacheman.c | 11 ++- ntoskrnl/cc/copy.c | 18 ++++- ntoskrnl/cc/fs.c | 4 +- ntoskrnl/cc/view.c | 173 ++++++++++++++++++++++++++++++++++++++--- ntoskrnl/include/internal/cc.h | 13 +++- ntoskrnl/mm/mminit.c | 78 ------------------- ntoskrnl/po/poshtdwn.c | 3 +- ntoskrnl/po/power.c | 3 +- 9 files changed, 205 insertions(+), 100 deletions(-) diff --git a/ntoskrnl/cache/newcc.h b/ntoskrnl/cache/newcc.h index adbf1c5d92..63f4841229 100644 --- a/ntoskrnl/cache/newcc.h +++ b/ntoskrnl/cache/newcc.h @@ -53,7 +53,7 @@ CcMdlWriteComplete2(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain); -VOID +BOOLEAN NTAPI CcInitView(VOID); diff --git a/ntoskrnl/cc/cacheman.c b/ntoskrnl/cc/cacheman.c index 4d62314ccd..2c2c2238c9 100644 --- a/ntoskrnl/cc/cacheman.c +++ b/ntoskrnl/cc/cacheman.c @@ -41,8 +41,15 @@ NTAPI INIT_FUNCTION CcInitializeCacheManager(VOID) { - CcInitView(); - return TRUE; + return CcInitView(); +} + +VOID +NTAPI +CcShutdownSystem(VOID) +{ + /* Inform the lazy writer it has to stop activity */ + CcShutdownLazyWriter(); } /* diff --git a/ntoskrnl/cc/copy.c b/ntoskrnl/cc/copy.c index 15c6ceb81b..dadae020c7 100644 --- a/ntoskrnl/cc/copy.c +++ b/ntoskrnl/cc/copy.c @@ -34,6 +34,8 @@ ULONG CcFastReadWait; ULONG CcFastReadNoWait; ULONG CcFastReadResourceMiss; +extern KEVENT iLazyWriterNotify; + /* FUNCTIONS *****************************************************************/ VOID @@ -516,14 +518,26 @@ CcFastCopyWrite ( } /* - * @unimplemented + * @implemented */ NTSTATUS NTAPI CcWaitForCurrentLazyWriterActivity ( VOID) { - UNIMPLEMENTED; + NTSTATUS Status; + + /* Lazy writer is done when its event is set */ + Status = KeWaitForSingleObject(&iLazyWriterNotify, + Executive, + KernelMode, + FALSE, + NULL); + if (!NT_SUCCESS(Status)) + { + return Status; + } + return STATUS_SUCCESS; } diff --git a/ntoskrnl/cc/fs.c b/ntoskrnl/cc/fs.c index 4958478f3f..76a073af1b 100644 --- a/ntoskrnl/cc/fs.c +++ b/ntoskrnl/cc/fs.c @@ -20,7 +20,7 @@ /* GLOBALS *****************************************************************/ extern KGUARDED_MUTEX ViewLock; -extern ULONG DirtyPageCount; +extern ULONG CcTotalDirtyPages; NTSTATUS CcRosInternalFreeVacb(PROS_VACB Vacb); @@ -239,7 +239,7 @@ CcPurgeCacheSection ( if (Vacb->Dirty) { RemoveEntryList(&Vacb->DirtyVacbListEntry); - DirtyPageCount -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; } RemoveEntryList(&Vacb->CacheMapVacbListEntry); InsertHeadList(&FreeList, &Vacb->CacheMapVacbListEntry); diff --git a/ntoskrnl/cc/view.c b/ntoskrnl/cc/view.c index 0e37b77efc..8fb7f5333c 100644 --- a/ntoskrnl/cc/view.c +++ b/ntoskrnl/cc/view.c @@ -43,7 +43,6 @@ LIST_ENTRY DirtyVacbListHead; static LIST_ENTRY VacbLruListHead; -ULONG DirtyPageCount = 0; KGUARDED_MUTEX ViewLock; @@ -51,6 +50,27 @@ NPAGED_LOOKASIDE_LIST iBcbLookasideList; static NPAGED_LOOKASIDE_LIST SharedCacheMapLookasideList; static NPAGED_LOOKASIDE_LIST VacbLookasideList; +/* Counters: + * - Amount of pages flushed by lazy writer + * - Number of times lazy writer ran + */ +ULONG CcLazyWritePages = 0; +ULONG CcLazyWriteIos = 0; + +/* Internal vars (MS): + * - Threshold above which lazy writer will start action + * - Amount of dirty pages + */ +ULONG CcDirtyPageThreshold = 0; +ULONG CcTotalDirtyPages = 0; + +/* Internal vars (ROS): + * - Event to notify lazy writer to shutdown + * - Event to inform watchers lazy writer is done for this loop + */ +KEVENT iLazyWriterShutdown; +KEVENT iLazyWriterNotify; + #if DBG static void CcRosVacbIncRefCount_(PROS_VACB vacb, const char* file, int line) { @@ -145,7 +165,7 @@ CcRosFlushVacb ( Vacb->Dirty = FALSE; RemoveEntryList(&Vacb->DirtyVacbListEntry); - DirtyPageCount -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; CcRosVacbDecRefCount(Vacb); KeReleaseSpinLock(&Vacb->SharedCacheMap->CacheMapLock, oldIrql); @@ -160,7 +180,8 @@ NTAPI CcRosFlushDirtyPages ( ULONG Target, PULONG Count, - BOOLEAN Wait) + BOOLEAN Wait, + BOOLEAN CalledFromLazy) { PLIST_ENTRY current_entry; PROS_VACB current; @@ -191,6 +212,14 @@ CcRosFlushDirtyPages ( CcRosVacbIncRefCount(current); + /* When performing lazy write, don't handle temporary files */ + if (CalledFromLazy && + BooleanFlagOn(current->SharedCacheMap->FileObject->Flags, FO_TEMPORARY_FILE)) + { + CcRosVacbDecRefCount(current); + continue; + } + Locked = current->SharedCacheMap->Callbacks->AcquireForLazyWrite( current->SharedCacheMap->LazyWriteContext, Wait); if (!Locked) @@ -239,8 +268,22 @@ CcRosFlushDirtyPages ( } else { - (*Count) += VACB_MAPPING_GRANULARITY / PAGE_SIZE; - Target -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + ULONG PagesFreed; + + /* How many pages did we free? */ + PagesFreed = VACB_MAPPING_GRANULARITY / PAGE_SIZE; + (*Count) += PagesFreed; + + /* Make sure we don't overflow target! */ + if (Target < PagesFreed) + { + /* If we would have, jump to zero directly */ + Target = 0; + } + else + { + Target -= PagesFreed; + } } current_entry = DirtyVacbListHead.Flink; @@ -253,6 +296,60 @@ CcRosFlushDirtyPages ( return STATUS_SUCCESS; } +/* FIXME: Someday this could somewhat implement write-behind/read-ahead */ +VOID +NTAPI +CciLazyWriter(PVOID Unused) +{ + LARGE_INTEGER OneSecond; + + OneSecond.QuadPart = (LONGLONG)-1*1000*1000*10; + + while (TRUE) + { + NTSTATUS Status; + ULONG Target, Count = 0; + + /* One per second or until we have to stop */ + Status = KeWaitForSingleObject(&iLazyWriterShutdown, + Executive, + KernelMode, + FALSE, + &OneSecond); + + /* If we succeeed, we've to stop running! */ + if (Status == STATUS_SUCCESS) + { + break; + } + + /* We're not sleeping anymore */ + KeClearEvent(&iLazyWriterNotify); + + /* Only start operations if above threshold */ + DPRINT("TS: %lu, Count: %lu\n", CcDirtyPageThreshold, CcTotalDirtyPages); + if (CcTotalDirtyPages > CcDirtyPageThreshold) + { + /* Our target is one-eighth of the dirty pages */ + Target = CcTotalDirtyPages / 8; + if (Target != 0) + { + /* Flush! */ + DPRINT("Lazy writer starting (%d)\n", Target); + CcRosFlushDirtyPages(Target, &Count, FALSE, TRUE); + + /* And update stats */ + CcLazyWritePages += Count; + ++CcLazyWriteIos; + DPRINT("Lazy writer done (%d)\n", Count); + } + } + + /* Inform people waiting on us that we're done */ + KeSetEvent(&iLazyWriterNotify, IO_DISK_INCREMENT, FALSE); + } +} + NTSTATUS CcRosTrimCache ( ULONG Target, @@ -346,7 +443,7 @@ retry: if ((Target > 0) && !FlushedPages) { /* Flush dirty pages to disk */ - CcRosFlushDirtyPages(Target, &PagesFreed, FALSE); + CcRosFlushDirtyPages(Target, &PagesFreed, FALSE, FALSE); FlushedPages = TRUE; /* We can only swap as many pages as we flushed */ @@ -403,7 +500,7 @@ CcRosReleaseVacb ( if (!WasDirty && Vacb->Dirty) { InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); - DirtyPageCount += VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; } if (Mapped) @@ -499,7 +596,7 @@ CcRosMarkDirtyVacb ( if (!Vacb->Dirty) { InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); - DirtyPageCount += VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; } else { @@ -552,7 +649,7 @@ CcRosUnmapVacb ( if (!WasDirty && NowDirty) { InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); - DirtyPageCount += VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; } CcRosVacbDecRefCount(Vacb); @@ -1014,7 +1111,7 @@ CcRosDeleteFileCache ( if (current->Dirty) { RemoveEntryList(¤t->DirtyVacbListEntry); - DirtyPageCount -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; DPRINT1("Freeing dirty VACB\n"); } InsertHeadList(&FreeList, ¤t->CacheMapVacbListEntry); @@ -1230,11 +1327,24 @@ CcGetFileObjectFromSectionPtrs ( } VOID +NTAPI +CcShutdownLazyWriter ( + VOID) +{ + /* Simply set the event, lazy writer will stop when it's done */ + KeSetEvent(&iLazyWriterShutdown, IO_DISK_INCREMENT, FALSE); +} + +BOOLEAN INIT_FUNCTION NTAPI CcInitView ( VOID) { + HANDLE LazyWriter; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + DPRINT("CcInitView()\n"); InitializeListHead(&DirtyVacbListHead); @@ -1264,7 +1374,50 @@ CcInitView ( MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache); + /* Initialize lazy writer events */ + KeInitializeEvent(&iLazyWriterShutdown, SynchronizationEvent, FALSE); + KeInitializeEvent(&iLazyWriterNotify, NotificationEvent, FALSE); + + /* Define lazy writer threshold, depending on system type */ + switch (MmQuerySystemSize()) + { + case MmSmallSystem: + CcDirtyPageThreshold = MmNumberOfPhysicalPages / 8; + break; + + case MmMediumSystem: + CcDirtyPageThreshold = MmNumberOfPhysicalPages / 4; + break; + + case MmLargeSystem: + CcDirtyPageThreshold = MmNumberOfPhysicalPages / 8 + MmNumberOfPhysicalPages / 4; + break; + } + + /* Start the lazy writer thread */ + InitializeObjectAttributes(&ObjectAttributes, + NULL, + OBJ_KERNEL_HANDLE, + NULL, + NULL); + Status = PsCreateSystemThread(&LazyWriter, + THREAD_ALL_ACCESS, + &ObjectAttributes, + NULL, + NULL, + CciLazyWriter, + NULL); + if (!NT_SUCCESS(Status)) + { + return FALSE; + } + + /* Handle is not needed */ + ObCloseHandle(LazyWriter, KernelMode); + CcInitCacheZeroPage(); + + return TRUE; } /* EOF */ diff --git a/ntoskrnl/include/internal/cc.h b/ntoskrnl/include/internal/cc.h index 58d2b15a50..b1bb1ab165 100644 --- a/ntoskrnl/include/internal/cc.h +++ b/ntoskrnl/include/internal/cc.h @@ -240,10 +240,14 @@ CcRosGetVacb( PROS_VACB *Vacb ); -VOID +BOOLEAN NTAPI CcInitView(VOID); +VOID +NTAPI +CcShutdownLazyWriter(VOID); + NTSTATUS NTAPI CcReadVirtualAddress(PROS_VACB Vacb); @@ -287,7 +291,8 @@ NTAPI CcRosFlushDirtyPages( ULONG Target, PULONG Count, - BOOLEAN Wait + BOOLEAN Wait, + BOOLEAN CalledFromLazy ); VOID @@ -342,6 +347,10 @@ NTSTATUS NTAPI CcTryToInitializeFileCache(PFILE_OBJECT FileObject); +VOID +NTAPI +CcShutdownSystem(VOID); + FORCEINLINE NTSTATUS CcRosAcquireVacbLock( diff --git a/ntoskrnl/mm/mminit.c b/ntoskrnl/mm/mminit.c index 3fff72b771..7f756cb778 100644 --- a/ntoskrnl/mm/mminit.c +++ b/ntoskrnl/mm/mminit.c @@ -19,9 +19,6 @@ VOID NTAPI MiInitializeUserPfnBitmap(VOID); -HANDLE MpwThreadHandle; -KEVENT MpwThreadEvent; - BOOLEAN Mm64BitPhysicalAddress = FALSE; ULONG MmReadClusterSize; // @@ -169,76 +166,6 @@ MiDbgDumpAddressSpace(VOID) "Non Paged Pool Expansion PTE Space"); } -VOID -NTAPI -MmMpwThreadMain(PVOID Parameter) -{ - NTSTATUS Status; -#ifndef NEWCC - ULONG PagesWritten; -#endif - LARGE_INTEGER Timeout; - - UNREFERENCED_PARAMETER(Parameter); - - Timeout.QuadPart = -50000000; - - for(;;) - { - Status = KeWaitForSingleObject(&MpwThreadEvent, - 0, - KernelMode, - FALSE, - &Timeout); - if (!NT_SUCCESS(Status)) - { - DbgPrint("MpwThread: Wait failed\n"); - KeBugCheck(MEMORY_MANAGEMENT); - return; - } - -#ifndef NEWCC - PagesWritten = 0; - - // XXX arty -- we flush when evicting pages or destorying cache - // sections. - CcRosFlushDirtyPages(128, &PagesWritten, FALSE); -#endif - } -} - -NTSTATUS -NTAPI -INIT_FUNCTION -MmInitMpwThread(VOID) -{ - KPRIORITY Priority; - NTSTATUS Status; - CLIENT_ID MpwThreadId; - - KeInitializeEvent(&MpwThreadEvent, SynchronizationEvent, FALSE); - - Status = PsCreateSystemThread(&MpwThreadHandle, - THREAD_ALL_ACCESS, - NULL, - NULL, - &MpwThreadId, - MmMpwThreadMain, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - Priority = 27; - NtSetInformationThread(MpwThreadHandle, - ThreadPriority, - &Priority, - sizeof(Priority)); - - return(STATUS_SUCCESS); -} - NTSTATUS NTAPI INIT_FUNCTION @@ -338,11 +265,6 @@ MmInitSystem(IN ULONG Phase, */ MiInitBalancerThread(); - /* - * Initialise the modified page writer. - */ - MmInitMpwThread(); - /* Initialize the balance set manager */ MmInitBsmThread(); diff --git a/ntoskrnl/po/poshtdwn.c b/ntoskrnl/po/poshtdwn.c index 3ebf899bd5..04618c9f54 100644 --- a/ntoskrnl/po/poshtdwn.c +++ b/ntoskrnl/po/poshtdwn.c @@ -279,11 +279,10 @@ PopGracefulShutdown(IN PVOID Context) CmShutdownSystem(); /* Note that modified pages should be written here (MiShutdownSystem) */ -#ifdef NEWCC + /* Flush all user files before we start shutting down IO */ /* This is where modified pages are written back by the IO manager */ CcShutdownSystem(); -#endif /* In this step, the I/O manager does last-chance shutdown notification */ DPRINT("I/O manager shutting down in phase 1\n"); diff --git a/ntoskrnl/po/power.c b/ntoskrnl/po/power.c index 9b96b6016e..2dee988b34 100644 --- a/ntoskrnl/po/power.c +++ b/ntoskrnl/po/power.c @@ -952,7 +952,8 @@ NtSetSystemPowerState(IN POWER_ACTION SystemAction, #ifndef NEWCC /* Flush dirty cache pages */ - CcRosFlushDirtyPages(-1, &Dummy, FALSE); //HACK: We really should wait here! + /* XXX: Is that still mandatory? As now we'll wait on lazy writer to complete? */ + CcRosFlushDirtyPages(-1, &Dummy, FALSE, FALSE); //HACK: We really should wait here! #else Dummy = 0; #endif
6 years, 11 months
1
0
0
0
← Newer
1
...
8
9
10
11
12
13
14
...
38
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Results per page:
10
25
50
100
200