d0vgan / nppexec

NppExec (plugin for Notepad++)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

New thread to check if `npes_saved.txt` has changed

Gitoffthelawn opened this issue · comments

Thanks for the update to v0.8.1

I was reviewing the code changes, and have 3 questions/concerns about b75cd49

Many people keep Notepad++ open much of the day. This new code appears to be creating a new thread to check if npes_saved.txt has changed while Notepad++ is running.

  1. How often is this check taking place?
  2. Is a new thread created/destroyed each time the check takes place, or is it a single thread that exists for the entire duration that Notepad++ is running?
  3. Would it be possible for you to add a toggle so the user can disable this checking?

Thank you again for the helpful tool.

This thread is created when NppExec.dll is loaded (i.e. when Notepad++ starts) and this thread spends most of its time here:

::WaitForMultipleObjects(nObjs, hWaitObjs.get(), FALSE, INFINITE)

I.e. it uses 0% of CPU during 99% of the time.
When any file is modified in the "Notepad++\plugins\Config" folder, one of the hWaitObjs becomes signaled (because of FindFirstChangeNotification) and NppExec checks whether the last modification time of "npes_saved.txt" is changed or not. If it is changed, NppExec marks this file as "modified" but does not actually re-read this file. This file is re-read only when any script from this file is about to be accessed.

The "NppExec_TechInfo.txt" mentions the WatchScriptFile opton that can be used to disable the watching.

Thanks so much for your detailed explanation.

If you're willing, I think you may be able to expand my knowledge a bit.

What is the underlying mechanism that allows hWaitObjs (via FindFirstChangeNotification) to be notified of the change to the folder? Is it a new OS thread that gets added to constantly watch the folder? Or is there an existing OS thread always doing this regardless of whether or not nppexec is running? Or is it a completely different mechanism?

The FindFirstChangeNotification returns a HANDLE that can be passed to WaitForSingleObject/WaitForMultipleObjects:
https://docs.microsoft.com/en-us/windows/win32/fileio/obtaining-directory-change-notifications
The WaitForSingleObject/WaitForMultipleObjects returns when there is a change inside the directory being watched.
Then FindNextChangeNotification must be called to continue to watch the directory.
So it looks logical to introduce a background thread that calls FindFirstChangeNotification first and then calls FindNextChangeNotification in a loop.
There is an alternate approach based on ReadDirectoryChangesW, but its usage is too hardcore even for me with my 20 years of experience with WinAPI :)

Thanks. I've read what you wrote, and I'm going to have to come back and read it a few more times.

When you wrote "So it looks logical to introduce a background thread...", were you referring to yourself or the Windows OS? I'm thinking the former, but it's best for me to ask than to guess... :)

Regarding the background thread - yes, I was referring to myself :) Basically, the main thread is responsible for handling UI actions (such as reacting to menu items, pressing buttons, typing something in NppExec's Console and so on), so background threads are a perfect way to detach the actual processing of some time-consuming operations from UI actions that casue these operations. That is why NppExec's commands and scripts are processed in a background thread - to avoid locking (non-respondence) of the UI while running the commands/scripts. The same is with waiting for the asynchronous result of FindFirstChangeNotification/FindNextChangeNotification (the waiting is done by means of WaitForSingleObject/WaitForMultipleObjects) - a background thread is a perfect way to detach these operations from any other processing.
By the way, you can monitor thread activity and CPU usage via e.g. Process Explorer ( https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer ) or Process Hacker 3 ( https://processhacker.sourceforge.io/nightly.php ).