From fd41b5751ecf6b54fbe4239cc3f6c1289d1b89eb Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Sun, 18 Jun 2017 00:54:41 +0100 Subject: [PATCH] If a service stops and won't restart, release explicit activation. --- src/service.cc | 6 ++++ src/service.h | 2 +- src/tests/tests.cc | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/service.cc b/src/service.cc index 90d5b2e..2d83960 100644 --- a/src/service.cc +++ b/src/service.cc @@ -1041,6 +1041,12 @@ void service_record::do_stop() noexcept { if (pinned_started) return; + if (start_explicit && ! do_auto_restart()) { + start_explicit = false; + release(); + if (required_by == 0) return; // release will re-call us anyway + } + if (service_state != service_state_t::STARTED) { if (service_state == service_state_t::STARTING) { if (! can_interrupt_start()) { diff --git a/src/service.h b/src/service.h index 8313360..e3f40b1 100644 --- a/src/service.h +++ b/src/service.h @@ -794,7 +794,7 @@ class service_set // Stop the specified service. Its active mark will be cleared. void stop_service(service_record *svc) { - svc->stop(); + svc->stop(true); processQueues(); } diff --git a/src/tests/tests.cc b/src/tests/tests.cc index 12e2095..d1f350a 100644 --- a/src/tests/tests.cc +++ b/src/tests/tests.cc @@ -3,6 +3,8 @@ #include "service.h" +// Test 1: starting a service starts dependencies; stopping the service releases and +// stops dependencies. void test1() { service_set sset; @@ -33,6 +35,8 @@ void test1() assert(s1->getState() == service_state_t::STOPPED); } +// Test 2: Multiple dependents will hold a dependency active if one of the dependents is +// stopped/released. void test2() { service_set sset; @@ -73,6 +77,66 @@ void test2() assert(s1->getState() == service_state_t::STOPPED); } +// Test 3: stopping a dependency causes its dependents to stop. +void test3() +{ + service_set sset; + + service_record *s1 = new service_record(&sset, "test-service-1", service_type::INTERNAL, {}, {}); + service_record *s2 = new service_record(&sset, "test-service-2", service_type::INTERNAL, {s1}, {}); + service_record *s3 = new service_record(&sset, "test-service-3", service_type::INTERNAL, {s2}, {}); + sset.add_service(s1); + sset.add_service(s2); + sset.add_service(s3); + + assert(sset.find_service("test-service-1") == s1); + assert(sset.find_service("test-service-2") == s2); + assert(sset.find_service("test-service-3") == s3); + + // Start all three services: + sset.start_service(s3); + + // Now stop s1, which should also force s2 and s3 to stop: + sset.stop_service(s1); + + assert(s3->getState() == service_state_t::STOPPED); + assert(s2->getState() == service_state_t::STOPPED); + assert(s1->getState() == service_state_t::STOPPED); +} + +// Test 4: an explicitly activated service with automatic restart will restart if it +// stops due to a dependency stopping, therefore also causing the dependency to restart. +void test4() +{ + service_set sset; + + service_record *s1 = new service_record(&sset, "test-service-1", service_type::INTERNAL, {}, {}); + service_record *s2 = new service_record(&sset, "test-service-2", service_type::INTERNAL, {s1}, {}); + service_record *s3 = new service_record(&sset, "test-service-3", service_type::INTERNAL, {s2}, {}); + s2->setAutoRestart(true); + sset.add_service(s1); + sset.add_service(s2); + sset.add_service(s3); + + assert(sset.find_service("test-service-1") == s1); + assert(sset.find_service("test-service-2") == s2); + assert(sset.find_service("test-service-3") == s3); + + // Start all three services: + sset.start_service(s3); + + // Also explicitly activate s2: + sset.start_service(s2); + + // Now stop s1, which should also force s2 and s3 to stop. + // s2 (and therefore s1) should restart: + sset.stop_service(s1); + + assert(s3->getState() == service_state_t::STOPPED); + assert(s2->getState() == service_state_t::STARTED); + assert(s1->getState() == service_state_t::STARTED); +} + int main(int argc, char **argv) { std::cout << "test1... "; @@ -82,4 +146,12 @@ int main(int argc, char **argv) std::cout << "test2... "; test2(); std::cout << "PASSED" << std::endl; + + std::cout << "test3... "; + test3(); + std::cout << "PASSED" << std::endl; + + std::cout << "test4... "; + test4(); + std::cout << "PASSED" << std::endl; } -- 2.25.1