diff --git a/IntelPresentMon/PMInstallerLib/Library.wxs b/IntelPresentMon/PMInstallerLib/Library.wxs
index 4edfcbfa6..d938573e1 100644
--- a/IntelPresentMon/PMInstallerLib/Library.wxs
+++ b/IntelPresentMon/PMInstallerLib/Library.wxs
@@ -74,7 +74,33 @@
Impersonate="no"
Return="ignore" />
+
+
+
+
+
+ NOT REMOVE
+ NOT REMOVE
1
diff --git a/IntelPresentMon/PresentMonService/CliOptions.h b/IntelPresentMon/PresentMonService/CliOptions.h
index 7665a3a90..79a3bb92a 100644
--- a/IntelPresentMon/PresentMonService/CliOptions.h
+++ b/IntelPresentMon/PresentMonService/CliOptions.h
@@ -26,6 +26,7 @@ namespace clio
private: Group gd_{ this, "Debugging", "Aids in debugging this tool" }; public:
Flag debug{ this, "--debug,-d", "Stall service by running in a loop after startup waiting for debugger to connect" };
Option timedStop{ this, "--timed-stop", -1, "Signal stop event after specified number of milliseconds" };
+ Option recoveryFailCount{ this, "--recovery-fail-count", 0, "Failure count SCM passes when it starts the service on recovery" };
private: Group gr_{ this, "Playback", "Playback of recorded ETL files" }; public:
Option etlTestFile{ this, "--etl-test-file", "", "Etl test file including necessary path", CLI::ExistingFile };
diff --git a/IntelPresentMon/PresentMonService/Service.cpp b/IntelPresentMon/PresentMonService/Service.cpp
index 8cf103424..6f58f7f0b 100644
--- a/IntelPresentMon/PresentMonService/Service.cpp
+++ b/IntelPresentMon/PresentMonService/Service.cpp
@@ -5,7 +5,6 @@
#include
#include
#include
-#include
#include "PMMainThread.h"
#include
#include
@@ -134,7 +133,7 @@ void ConcreteService::ServiceInit()
FALSE, // auto reset event
FALSE, // not signaled
NULL); // no name
- if (mServiceStopEventHandle == nullptr) {
+ if (mResetPowerTelemetryEventHandle == nullptr) {
ReportServiceStatus(SERVICE_STOPPED, GetLastError(), 0);
return;
}
diff --git a/IntelPresentMon/PresentMonService/ServiceMain.cpp b/IntelPresentMon/PresentMonService/ServiceMain.cpp
index c9e79006f..7ba4e80a3 100644
--- a/IntelPresentMon/PresentMonService/ServiceMain.cpp
+++ b/IntelPresentMon/PresentMonService/ServiceMain.cpp
@@ -50,6 +50,10 @@ int CommonEntry(DWORD argc, LPTSTR* argv, bool asApp)
log::GetLevelName(log::GlobalPolicy::Get().GetLogLevel()),
log::GetLevelName(PMLOG_BUILD_LEVEL_)));
+ if (const auto failCount = clio::Options::Get().recoveryFailCount.AsOptional()) {
+ pmlog_warn(std::format("SCM recovery start, fail count {}.", *failCount)).no_trace();
+ }
+
if (asApp) {
auto& svc = ConsoleDebugMockService::Get();
svc.Run();
diff --git a/README-Service.md b/README-Service.md
index 8317544c6..dfa359487 100644
--- a/README-Service.md
+++ b/README-Service.md
@@ -18,4 +18,22 @@ PresentMonAPI.h, PresentMonAPI2Loader.lib, and PresentMonAPI2Loader.dll are opti
## Diagnostics
-All of the PresentMonAPI functions return an enum type PM_STATUS that indicates success/failure and can give a hint as to the cause of any failure. For more detailed diagnostic messages, refer to PresentMonDiagnostics.h found in the PresentMonAPI2 project directory.
\ No newline at end of file
+All of the PresentMonAPI functions return an enum type PM_STATUS that indicates success/failure and can give a hint as to the cause of any failure. For more detailed diagnostic messages, refer to PresentMonDiagnostics.h found in the PresentMonAPI2 project directory.
+
+# Failure recovery
+
+The installer configures `PresentMonSharedService` so Windows starts it again after an abnormal process exit, then stops trying. The Recovery action is "Run a program", not "Restart the Service". Restart does not take a command line. The program is `sc.exe start PresentMonSharedService --recovery-fail-count %1%`. `%1%` is the failure-count placeholder SCM substitutes when it runs the command (the same placeholder the Recovery tab checkbox documents as `/fail=%1%`). `sc.exe start` passes `--recovery-fail-count N` through to the service. The command string is fixed at install time. The service does not register or rewrite it.
+
+| Failure in the window | Action | Holdoff |
+| --- | --- | --- |
+| 1st | start with `--recovery-fail-count 1` | 2 seconds |
+| 2nd | start with `--recovery-fail-count 2` | 15 seconds |
+| 3rd | start with `--recovery-fail-count 3` | 60 seconds |
+| 4th | start with `--recovery-fail-count 4` | 5 minutes |
+| 5th and later | stay stopped | |
+
+The failure count resets after 30 minutes with no failure. That reset does not start the service. A later start gets a fresh budget only after those 30 minutes have elapsed. A clean stop (`sc.exe stop`) does not count as a failure.
+
+On a recovery start the service log contains `SCM recovery start, fail count N`. A normal start has no `--recovery-fail-count` argument and does not log that line.
+
+An existing client session is not reconnected. The next API call on that handle returns `PM_STATUS_SESSION_NOT_OPEN`. Opening a new session after the service is back is the caller's responsibility.