mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-16 00:33:22 +08:00
85 lines
3.0 KiB
C++
85 lines
3.0 KiB
C++
#include <Windows.h>
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <thread>
|
|
|
|
#include "service_lifetime.h"
|
|
|
|
int wmain(int argc, wchar_t** argv) {
|
|
if (argc == 4 && std::wstring(argv[1]) == L"--child") {
|
|
crossdesk::ServiceLifetimeWatcher watcher;
|
|
if (!watcher.Start(argv[2])) return 2;
|
|
HANDLE ready = OpenEventW(EVENT_MODIFY_STATE, FALSE, argv[3]);
|
|
if (!ready) return 3;
|
|
SetEvent(ready);
|
|
CloseHandle(ready);
|
|
Sleep(INFINITE); // The real watcher must terminate this child.
|
|
return 4;
|
|
}
|
|
|
|
wchar_t executable[32768]{};
|
|
if (!GetModuleFileNameW(nullptr, executable, 32768)) return 1;
|
|
for (bool abandon : {false, true}) {
|
|
const auto suffix = std::to_wstring(GetCurrentProcessId()) +
|
|
(abandon ? L"-abandon" : L"-release");
|
|
const auto name = L"Global\\CrossDeskLifetimeTest-" + suffix;
|
|
const auto ready_name = name + L"-ready";
|
|
HANDLE owned = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
|
HANDLE exit_owner = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
|
HANDLE ready = CreateEventW(nullptr, TRUE, FALSE, ready_name.c_str());
|
|
if (!owned || !exit_owner || !ready) return 1;
|
|
HANDLE lifetime = nullptr;
|
|
std::thread owner([&] {
|
|
lifetime = CreateMutexW(nullptr, TRUE, name.c_str());
|
|
SetEvent(owned);
|
|
WaitForSingleObject(exit_owner, INFINITE);
|
|
if (!abandon && lifetime) ReleaseMutex(lifetime);
|
|
});
|
|
WaitForSingleObject(owned, INFINITE);
|
|
bool ok = lifetime != nullptr;
|
|
if (ok) {
|
|
// Cancellation during an ordinary helper exit must not wait for or
|
|
// release the service's ownership.
|
|
crossdesk::ServiceLifetimeWatcher cancellation;
|
|
ok = cancellation.Start(name);
|
|
}
|
|
std::wstring command = L"\"" + std::wstring(executable) + L"\" --child \"" +
|
|
name + L"\" \"" + ready_name + L"\"";
|
|
STARTUPINFOW startup{};
|
|
startup.cb = sizeof(startup);
|
|
PROCESS_INFORMATION child{};
|
|
if (ok)
|
|
ok = CreateProcessW(executable, command.data(), nullptr, nullptr, FALSE,
|
|
CREATE_NO_WINDOW, nullptr, nullptr, &startup,
|
|
&child) != FALSE;
|
|
if (ok)
|
|
ok = WaitForSingleObject(ready, 10000) == WAIT_OBJECT_0 &&
|
|
WaitForSingleObject(child.hProcess, 0) == WAIT_TIMEOUT;
|
|
SetEvent(exit_owner);
|
|
owner.join();
|
|
if (ok) ok = WaitForSingleObject(child.hProcess, 5000) == WAIT_OBJECT_0;
|
|
DWORD exit_code = 0;
|
|
if (ok)
|
|
ok = GetExitCodeProcess(child.hProcess, &exit_code) &&
|
|
exit_code == ERROR_BROKEN_PIPE;
|
|
if (child.hProcess) {
|
|
if (!ok) TerminateProcess(child.hProcess, 1);
|
|
WaitForSingleObject(child.hProcess, 5000);
|
|
CloseHandle(child.hProcess);
|
|
CloseHandle(child.hThread);
|
|
}
|
|
if (lifetime) CloseHandle(lifetime);
|
|
CloseHandle(owned);
|
|
CloseHandle(exit_owner);
|
|
CloseHandle(ready);
|
|
if (!ok) {
|
|
std::cerr << "Service lifetime test failed, abandoned=" << abandon
|
|
<< '\n';
|
|
return 1;
|
|
}
|
|
}
|
|
std::cout
|
|
<< "Service release, crash and watcher cancellation checks passed\n";
|
|
}
|