From 88a03245879e4308cee33c01383efe0ca97fe90e Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Tue, 16 Oct 2018 22:45:05 +0100 Subject: [PATCH] control: add function to enable service. This adds a dependency, and starts the dependent service if not already started (and if the dependent is started/starting). --- src/control.cc | 48 ++++++++++++++++++++++++------------- src/includes/control-cmds.h | 3 +++ src/includes/control.h | 2 +- src/includes/service.h | 15 ++++++++++-- 4 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/control.cc b/src/control.cc index 3c5f3f1..755dff6 100644 --- a/src/control.cc +++ b/src/control.cc @@ -17,11 +17,11 @@ namespace { constexpr uint16_t cp_version = 1; // check for value in a set - template - inline bool contains(const T (&v)[N], int i) + template + inline bool contains(const T (&v)[N], U i) { return std::find_if(std::begin(v), std::end(v), - [=](T p){ return i == static_cast(p); }) != std::end(v); + [=](T p){ return i == static_cast(p); }) != std::end(v); } } @@ -92,6 +92,9 @@ bool control_conn_t::process_packet() if (pktType == DINIT_CP_QUERY_LOAD_MECH) { return query_load_mech(); } + if (pktType == DINIT_CP_ENABLESERVICE) { + return add_service_dep(true); + } // Unrecognized: give error response char outbuf[] = { DINIT_RP_BADREQ }; @@ -395,7 +398,7 @@ bool control_conn_t::list_services() } } -bool control_conn_t::add_service_dep() +bool control_conn_t::add_service_dep(bool do_enable) { // 1 byte packet type // 1 byte dependency type @@ -427,8 +430,8 @@ bool control_conn_t::add_service_dep() // Check dependency type is valid: int dep_type_int = rbuf[1]; - if (! contains({(int)dependency_type::MILESTONE, (int)dependency_type::REGULAR, - (int)dependency_type::WAITS_FOR}, dep_type_int)) { + if (! contains({dependency_type::MILESTONE, dependency_type::REGULAR, + dependency_type::WAITS_FOR}, dep_type_int)) { char badreqRep[] = { DINIT_RP_BADREQ }; if (! queue_packet(badreqRep, 1)) return false; bad_conn_close = true; @@ -476,22 +479,33 @@ bool control_conn_t::add_service_dep() dep_marks.clear(); dep_queue.clear(); + bool dep_exists = false; + service_dep * dep_record = nullptr; + // Prevent creation of duplicate dependency: for (auto &dep : from_service->get_dependencies()) { service_record * dep_to = dep.get_to(); if (dep_to == to_service && dep.dep_type == dep_type) { - // Dependency already exists: return success - char ack_rep[] = { DINIT_RP_ACK }; - if (! queue_packet(ack_rep, 1)) return false; - rbuf.consume(pkt_size); - chklen = 0; - return true; + // Dependency already exists + dep_exists = true; + dep_record = &dep; + break; } } - // Create dependency: - from_service->add_dep(to_service, dep_type); - services->process_queues(); + if (! dep_exists) { + // Create dependency: + dep_record = &(from_service->add_dep(to_service, dep_type)); + services->process_queues(); + } + + if (do_enable && contains({service_state_t::STARTED, service_state_t::STARTING}, + from_service->get_state())) { + // The dependency record is activated: mark it as holding acquisition of the dependency, and start + // the dependency. + dep_record->get_from()->start_dep(*dep_record); + services->process_queues(); + } char ack_rep[] = { DINIT_RP_ACK }; if (! queue_packet(ack_rep, 1)) return false; @@ -532,8 +546,8 @@ bool control_conn_t::rm_service_dep() // Check dependency type is valid: int dep_type_int = rbuf[1]; - if (! contains({(int)dependency_type::MILESTONE, (int)dependency_type::REGULAR, - (int)dependency_type::WAITS_FOR}, dep_type_int)) { + if (! contains({dependency_type::MILESTONE, dependency_type::REGULAR, + dependency_type::WAITS_FOR}, dep_type_int)) { char badreqRep[] = { DINIT_RP_BADREQ }; if (! queue_packet(badreqRep, 1)) return false; bad_conn_close = true; diff --git a/src/includes/control-cmds.h b/src/includes/control-cmds.h index f757b51..21f7de5 100644 --- a/src/includes/control-cmds.h +++ b/src/includes/control-cmds.h @@ -36,6 +36,9 @@ constexpr static int DINIT_CP_REM_DEP = 12; // Query service load path / mechanism: constexpr static int DINIT_CP_QUERY_LOAD_MECH = 13; +// Add a waits for dependency from one service to another, and start the dependency: +constexpr static int DINIT_CP_ENABLESERVICE = 14; + // Replies: // Reply: ACK/NAK to request diff --git a/src/includes/control.h b/src/includes/control.h index e0d3020..e2414d4 100644 --- a/src/includes/control.h +++ b/src/includes/control.h @@ -149,7 +149,7 @@ class control_conn_t : private service_listener bool list_services(); // Add a dependency between two services. - bool add_service_dep(); + bool add_service_dep(bool do_start = false); // Remove a dependency between two services. bool rm_service_dep(); diff --git a/src/includes/service.h b/src/includes/service.h index 390d5d0..de44277 100644 --- a/src/includes/service.h +++ b/src/includes/service.h @@ -626,7 +626,7 @@ class service_record return 0; } - const dep_list & get_dependencies() + dep_list & get_dependencies() { return depends_on; } @@ -634,7 +634,7 @@ class service_record // Add a dependency. Caller must ensure that the services are in an appropriate state and that // a circular dependency chain is not created. Propagation queues should be processed after // calling this. May throw std::bad_alloc. - void add_dep(service_record *to, dependency_type dep_type) + service_dep & add_dep(service_record *to, dependency_type dep_type) { depends_on.emplace_back(this, to, dep_type); try { @@ -651,6 +651,8 @@ class service_record depends_on.back().holding_acq = true; } } + + return depends_on.back(); } // Remove a dependency, of the given type, to the given service. Propagation queues should be processed @@ -674,6 +676,15 @@ class service_record } } } + + // Start a speficic dependency of this service. Should only be called if this service is in an + // appropriate state (started, starting). The dependency is marked as holding acquired; when + // this service stops, the dependency will be released and may also stop. + void start_dep(service_dep &dep) + { + dep.get_to()->require(); + dep.holding_acq = true; + } }; inline auto extract_prop_queue(service_record *sr) -> decltype(sr->prop_queue_node) & -- 2.25.1