From 16fe697820574aa91d2c379b6b3681bb06c4fdf4 Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Wed, 27 Dec 2017 00:58:35 +0000 Subject: [PATCH] Various minor cleanups. --- src/control.cc | 77 ++++++++++++++++++++--------------------- src/control.h | 73 +++++++++++++++++++------------------- src/dinit.cc | 2 +- src/dinitctl.cc | 16 ++++----- src/service-constants.h | 2 +- src/service-listener.h | 2 +- src/service.cc | 22 ++++++------ src/service.h | 35 ++++++++++++------- 8 files changed, 118 insertions(+), 111 deletions(-) diff --git a/src/control.cc b/src/control.cc index a3eaae2..8356f1c 100644 --- a/src/control.cc +++ b/src/control.cc @@ -1,11 +1,11 @@ #include "control.h" #include "service.h" -bool control_conn_t::processPacket() +bool control_conn_t::process_packet() { using std::string; - // Note that where we call queuePacket, we must generally check the return value. If it + // Note that where we call queue_packet, we must generally check the return value. If it // returns false it has either deleted the connection or marked it for deletion; we // shouldn't touch instance members after that point. @@ -14,19 +14,19 @@ bool control_conn_t::processPacket() // Responds with: // DINIT_RP_CVERSION, (2 byte) minimum compatible version, (2 byte) maximum compatible version char replyBuf[] = { DINIT_RP_CPVERSION, 0, 0, 0, 0 }; - if (! queuePacket(replyBuf, 1)) return false; + if (! queue_packet(replyBuf, 1)) return false; rbuf.consume(1); return true; } if (pktType == DINIT_CP_FINDSERVICE || pktType == DINIT_CP_LOADSERVICE) { - return processFindLoad(pktType); + return process_find_load(pktType); } if (pktType == DINIT_CP_STARTSERVICE || pktType == DINIT_CP_STOPSERVICE || pktType == DINIT_CP_WAKESERVICE || pktType == DINIT_CP_RELEASESERVICE) { - return processStartStop(pktType); + return process_start_stop(pktType); } if (pktType == DINIT_CP_UNPINSERVICE) { - return processUnpinService(); + return process_unpin_service(); } if (pktType == DINIT_CP_SHUTDOWN) { // Shutdown/reboot @@ -39,7 +39,7 @@ bool control_conn_t::processPacket() services->stop_all_services(sd_type); char ackBuf[] = { DINIT_RP_ACK }; - if (! queuePacket(ackBuf, 1)) return false; + if (! queue_packet(ackBuf, 1)) return false; // Clear the packet from the buffer rbuf.consume(2); @@ -47,19 +47,19 @@ bool control_conn_t::processPacket() return true; } if (pktType == DINIT_CP_LISTSERVICES) { - return listServices(); + return list_services(); } else { // Unrecognized: give error response char outbuf[] = { DINIT_RP_BADREQ }; - if (! queuePacket(outbuf, 1)) return false; + if (! queue_packet(outbuf, 1)) return false; bad_conn_close = true; iob.set_watches(OUT_EVENTS); } return true; } -bool control_conn_t::processFindLoad(int pktType) +bool control_conn_t::process_find_load(int pktType) { using std::string; @@ -76,7 +76,7 @@ bool control_conn_t::processFindLoad(int pktType) if (svcSize <= 0 || chklen > 1024) { // Queue error response / mark connection bad char badreqRep[] = { DINIT_RP_BADREQ }; - if (! queuePacket(badreqRep, 1)) return false; + if (! queue_packet(badreqRep, 1)) return false; bad_conn_close = true; iob.set_watches(OUT_EVENTS); return true; @@ -107,7 +107,7 @@ bool control_conn_t::processFindLoad(int pktType) if (record != nullptr) { // Allocate a service handle - handle_t handle = allocateServiceHandle(record); + handle_t handle = allocate_service_handle(record); std::vector rp_buf; rp_buf.reserve(7); rp_buf.push_back(DINIT_RP_SERVICERECORD); @@ -116,11 +116,11 @@ bool control_conn_t::processFindLoad(int pktType) rp_buf.push_back(*(((char *) &handle) + i)); } rp_buf.push_back(static_cast(record->get_target_state())); - if (! queuePacket(std::move(rp_buf))) return false; + if (! queue_packet(std::move(rp_buf))) return false; } else { std::vector rp_buf = { DINIT_RP_NOSERVICE }; - if (! queuePacket(std::move(rp_buf))) return false; + if (! queue_packet(std::move(rp_buf))) return false; } // Clear the packet from the buffer @@ -129,7 +129,7 @@ bool control_conn_t::processFindLoad(int pktType) return true; } -bool control_conn_t::processStartStop(int pktType) +bool control_conn_t::process_start_stop(int pktType) { using std::string; @@ -148,11 +148,11 @@ bool control_conn_t::processStartStop(int pktType) handle_t handle; rbuf.extract((char *) &handle, 2, sizeof(handle)); - service_record *service = findServiceForKey(handle); + service_record *service = find_service_for_key(handle); if (service == nullptr) { // Service handle is bad char badreqRep[] = { DINIT_RP_BADREQ }; - if (! queuePacket(badreqRep, 1)) return false; + if (! queue_packet(badreqRep, 1)) return false; bad_conn_close = true; iob.set_watches(OUT_EVENTS); return true; @@ -194,7 +194,7 @@ bool control_conn_t::processStartStop(int pktType) char ack_buf[] = { (char)(already_there ? DINIT_RP_ALREADYSS : DINIT_RP_ACK) }; - if (! queuePacket(ack_buf, 1)) return false; + if (! queue_packet(ack_buf, 1)) return false; } // Clear the packet from the buffer @@ -203,7 +203,7 @@ bool control_conn_t::processStartStop(int pktType) return true; } -bool control_conn_t::processUnpinService() +bool control_conn_t::process_unpin_service() { using std::string; @@ -220,11 +220,11 @@ bool control_conn_t::processUnpinService() handle_t handle; rbuf.extract((char *) &handle, 1, sizeof(handle)); - service_record *service = findServiceForKey(handle); + service_record *service = find_service_for_key(handle); if (service == nullptr) { // Service handle is bad char badreqRep[] = { DINIT_RP_BADREQ }; - if (! queuePacket(badreqRep, 1)) return false; + if (! queue_packet(badreqRep, 1)) return false; bad_conn_close = true; iob.set_watches(OUT_EVENTS); return true; @@ -233,7 +233,7 @@ bool control_conn_t::processUnpinService() service->unpin(); services->process_queues(); char ack_buf[] = { (char) DINIT_RP_ACK }; - if (! queuePacket(ack_buf, 1)) return false; + if (! queue_packet(ack_buf, 1)) return false; } // Clear the packet from the buffer @@ -242,13 +242,13 @@ bool control_conn_t::processUnpinService() return true; } -bool control_conn_t::listServices() +bool control_conn_t::list_services() { rbuf.consume(1); // clear request packet chklen = 0; try { - auto slist = services->listServices(); + auto slist = services->list_services(); for (auto sptr : slist) { std::vector pkt_buf; @@ -270,22 +270,22 @@ bool control_conn_t::listServices() pkt_buf[8+i] = name[i]; } - if (! queuePacket(std::move(pkt_buf))) return false; + if (! queue_packet(std::move(pkt_buf))) return false; } char ack_buf[] = { (char) DINIT_RP_LISTDONE }; - if (! queuePacket(ack_buf, 1)) return false; + if (! queue_packet(ack_buf, 1)) return false; return true; } catch (std::bad_alloc &exc) { - doOomClose(); + do_oom_close(); return true; } } -control_conn_t::handle_t control_conn_t::allocateServiceHandle(service_record *record) +control_conn_t::handle_t control_conn_t::allocate_service_handle(service_record *record) { bool is_unique = true; handle_t largest_seen = 0; @@ -309,8 +309,7 @@ control_conn_t::handle_t control_conn_t::allocateServiceHandle(service_record *r return candidate; } - -bool control_conn_t::queuePacket(const char *pkt, unsigned size) noexcept +bool control_conn_t::queue_packet(const char *pkt, unsigned size) noexcept { int in_flag = bad_conn_close ? 0 : IN_EVENTS; bool was_empty = outbuf.empty(); @@ -363,9 +362,9 @@ bool control_conn_t::queuePacket(const char *pkt, unsigned size) noexcept } } -// This queuePacket method is frustratingly similar to the one above, but the subtle differences +// This queue_packet method is frustratingly similar to the one above, but the subtle differences // make them extraordinary difficult to combine into a single method. -bool control_conn_t::queuePacket(std::vector &&pkt) noexcept +bool control_conn_t::queue_packet(std::vector &&pkt) noexcept { int in_flag = bad_conn_close ? 0 : IN_EVENTS; bool was_empty = outbuf.empty(); @@ -416,13 +415,13 @@ bool control_conn_t::queuePacket(std::vector &&pkt) noexcept } } -bool control_conn_t::rollbackComplete() noexcept +bool control_conn_t::rollback_complete() noexcept { char ackBuf[2] = { DINIT_ROLLBACK_COMPLETED, 2 }; - return queuePacket(ackBuf, 2); + return queue_packet(ackBuf, 2); } -bool control_conn_t::dataReady() noexcept +bool control_conn_t::data_ready() noexcept { int fd = iob.get_watched_fd(); @@ -444,10 +443,10 @@ bool control_conn_t::dataReady() noexcept // complete packet? if (rbuf.get_length() >= chklen) { try { - return !processPacket(); + return !process_packet(); } catch (std::bad_alloc &baexc) { - doOomClose(); + do_oom_close(); return false; } } @@ -465,7 +464,7 @@ bool control_conn_t::dataReady() noexcept return false; } -bool control_conn_t::sendData() noexcept +bool control_conn_t::send_data() noexcept { if (outbuf.empty() && bad_conn_close) { if (oom_close) { @@ -515,7 +514,7 @@ bool control_conn_t::sendData() noexcept control_conn_t::~control_conn_t() noexcept { close(iob.get_watched_fd()); - iob.deregister(*loop); + iob.deregister(loop); // Clear service listeners for (auto p : serviceKeyMap) { diff --git a/src/control.h b/src/control.h index be94fd8..a6389f3 100644 --- a/src/control.h +++ b/src/control.h @@ -49,34 +49,33 @@ class service_record; class control_conn_watcher : public eventloop_t::bidi_fd_watcher_impl { - inline rearm receiveEvent(eventloop_t &loop, int fd, int flags) noexcept; + inline rearm receive_event(eventloop_t &loop, int fd, int flags) noexcept; + + eventloop_t * event_loop; public: + control_conn_watcher(eventloop_t & event_loop_p) : event_loop(&event_loop_p) + { + // constructor + } + rearm read_ready(eventloop_t &loop, int fd) noexcept { - return receiveEvent(loop, fd, IN_EVENTS); + return receive_event(loop, fd, IN_EVENTS); } rearm write_ready(eventloop_t &loop, int fd) noexcept { - return receiveEvent(loop, fd, OUT_EVENTS); + return receive_event(loop, fd, OUT_EVENTS); } - - eventloop_t * eventLoop; - + void set_watches(int flags) { - eventloop_t::bidi_fd_watcher::set_watches(*eventLoop, flags); - } - - void registerWith(eventloop_t &loop, int fd, int flags) - { - this->eventLoop = &loop; - bidi_fd_watcher::add_watch(loop, fd, flags); + eventloop_t::bidi_fd_watcher::set_watches(*event_loop, flags); } }; -inline rearm control_conn_watcher::receiveEvent(eventloop_t &loop, int fd, int flags) noexcept +inline rearm control_conn_watcher::receive_event(eventloop_t &loop, int fd, int flags) noexcept { return control_conn_cb(&loop, this, flags); } @@ -87,14 +86,14 @@ class control_conn_t : private service_listener friend rearm control_conn_cb(eventloop_t *loop, control_conn_watcher *watcher, int revents); control_conn_watcher iob; - eventloop_t *loop; + eventloop_t &loop; service_set *services; bool bad_conn_close = false; // close when finished output? bool oom_close = false; // send final 'out of memory' indicator // The packet length before we need to re-check if the packet is complete. - // processPacket() will not be called until the packet reaches this size. + // process_packet() will not be called until the packet reaches this size. int chklen; // Receive buffer @@ -122,8 +121,8 @@ class control_conn_t : private service_listener // true (with bad_conn_close == true) if the packet was not successfully // queued (but a suitable error packate has been queued). // The in/out watch enabled state will also be set appropriately. - bool queuePacket(vector &&v) noexcept; - bool queuePacket(const char *pkt, unsigned size) noexcept; + bool queue_packet(vector &&v) noexcept; + bool queue_packet(const char *pkt, unsigned size) noexcept; // Process a packet. // Returns: true (with bad_conn_close == false) if successful @@ -132,29 +131,29 @@ class control_conn_t : private service_listener // (connection should be closed). // Throws: // std::bad_alloc - if an out-of-memory condition prevents processing - bool processPacket(); + bool process_packet(); // Process a STARTSERVICE/STOPSERVICE packet. May throw std::bad_alloc. - bool processStartStop(int pktType); + bool process_start_stop(int pktType); // Process a FINDSERVICE/LOADSERVICE packet. May throw std::bad_alloc. - bool processFindLoad(int pktType); + bool process_find_load(int pktType); // Process an UNPINSERVICE packet. May throw std::bad_alloc. - bool processUnpinService(); + bool process_unpin_service(); - bool listServices(); + bool list_services(); // Notify that data is ready to be read from the socket. Returns true if the connection should // be closed. - bool dataReady() noexcept; + bool data_ready() noexcept; - bool sendData() noexcept; + bool send_data() noexcept; // Allocate a new handle for a service; may throw std::bad_alloc - handle_t allocateServiceHandle(service_record *record); + handle_t allocate_service_handle(service_record *record); - service_record *findServiceForKey(uint32_t key) + service_record *find_service_for_key(uint32_t key) { try { return keyServiceMap.at(key); @@ -165,7 +164,7 @@ class control_conn_t : private service_listener } // Close connection due to out-of-memory condition. - void doOomClose() + void do_oom_close() { bad_conn_close = true; oom_close = true; @@ -175,7 +174,7 @@ class control_conn_t : private service_listener // Process service event broadcast. // Note that this can potentially be called during packet processing (upon issuing // service start/stop orders etc). - void serviceEvent(service_record * service, service_event event) noexcept final override + void service_event(service_record * service, service_event_t event) noexcept final override { // For each service handle corresponding to the event, send an information packet. auto range = serviceKeyMap.equal_range(service); @@ -194,24 +193,24 @@ class control_conn_t : private service_listener pkt.push_back(*p++); } pkt.push_back(static_cast(event)); - queuePacket(std::move(pkt)); + queue_packet(std::move(pkt)); ++i; } } catch (std::bad_alloc &exc) { - doOomClose(); + do_oom_close(); } } public: - control_conn_t(eventloop_t * loop, service_set * services_p, int fd) - : loop(loop), services(services_p), chklen(0) + control_conn_t(eventloop_t &loop, service_set * services_p, int fd) + : iob(loop), loop(loop), services(services_p), chklen(0) { - iob.registerWith(*loop, fd, IN_EVENTS); + iob.add_watch(loop, fd, IN_EVENTS); active_control_conns++; } - bool rollbackComplete() noexcept; + bool rollback_complete() noexcept; virtual ~control_conn_t() noexcept; }; @@ -222,13 +221,13 @@ static rearm control_conn_cb(eventloop_t * loop, control_conn_watcher * watcher, char * cc_addr = (reinterpret_cast(watcher)) - offsetof(control_conn_t, iob); control_conn_t *conn = reinterpret_cast(cc_addr); if (revents & IN_EVENTS) { - if (conn->dataReady()) { + if (conn->data_ready()) { delete conn; return rearm::REMOVED; } } if (revents & OUT_EVENTS) { - if (conn->sendData()) { + if (conn->send_data()) { delete conn; return rearm::REMOVED; } diff --git a/src/dinit.cc b/src/dinit.cc index 86e67db..52c51c8 100644 --- a/src/dinit.cc +++ b/src/dinit.cc @@ -432,7 +432,7 @@ static void control_socket_cb(eventloop_t *loop, int sockfd) if (newfd != -1) { try { - new control_conn_t(loop, services, newfd); // will delete itself when it's finished + new control_conn_t(*loop, services, newfd); // will delete itself when it's finished } catch (std::exception &exc) { log(loglevel_t::ERROR, "Accepting control connection: ", exc.what()); diff --git a/src/dinitctl.cc b/src/dinitctl.cc index d431ac8..82468e9 100644 --- a/src/dinitctl.cc +++ b/src/dinitctl.cc @@ -375,16 +375,16 @@ static int startStopService(int socknum, const char *service_name, Command comma return 0; } - service_event completionEvent; - service_event cancelledEvent; + service_event_t completionEvent; + service_event_t cancelledEvent; if (do_stop) { - completionEvent = service_event::STOPPED; - cancelledEvent = service_event::STOPCANCELLED; + completionEvent = service_event_t::STOPPED; + cancelledEvent = service_event_t::STOPCANCELLED; } else { - completionEvent = service_event::STARTED; - cancelledEvent = service_event::STARTCANCELLED; + completionEvent = service_event_t::STARTED; + cancelledEvent = service_event_t::STARTCANCELLED; } // Wait until service started: @@ -397,7 +397,7 @@ static int startStopService(int socknum, const char *service_name, Command comma if (rbuffer[0] == DINIT_IP_SERVICEEVENT) { handle_t ev_handle; rbuffer.extract((char *) &ev_handle, 2, sizeof(ev_handle)); - service_event event = static_cast(rbuffer[2 + sizeof(ev_handle)]); + service_event_t event = static_cast(rbuffer[2 + sizeof(ev_handle)]); if (ev_handle == handle) { if (event == completionEvent) { if (verbose) { @@ -411,7 +411,7 @@ static int startStopService(int socknum, const char *service_name, Command comma } return 1; } - else if (! do_stop && event == service_event::FAILEDSTART) { + else if (! do_stop && event == service_event_t::FAILEDSTART) { if (verbose) { cout << "Service failed to start." << endl; } diff --git a/src/service-constants.h b/src/service-constants.h index 0cd5a2d..ad3cc2b 100644 --- a/src/service-constants.h +++ b/src/service-constants.h @@ -22,7 +22,7 @@ enum class service_type { }; /* Service events */ -enum class service_event { +enum class service_event_t { STARTED, // Service was started (reached STARTED state) STOPPED, // Service was stopped (reached STOPPED state) FAILEDSTART, // Service failed to start (possibly due to dependency failing) diff --git a/src/service-listener.h b/src/service-listener.h index a5c1269..34b64ed 100644 --- a/src/service-listener.h +++ b/src/service-listener.h @@ -12,7 +12,7 @@ class service_listener // An event occurred on the service being observed. // Listeners must not be added or removed during event notification. - virtual void serviceEvent(service_record * service, service_event event) noexcept = 0; + virtual void service_event(service_record * service, service_event_t event) noexcept = 0; }; #endif diff --git a/src/service.cc b/src/service.cc index 838d7ee..9779f35 100644 --- a/src/service.cc +++ b/src/service.cc @@ -110,7 +110,7 @@ void service_record::stopped() noexcept } log_service_stopped(service_name); - notify_listeners(service_event::STOPPED); + notify_listeners(service_event_t::STOPPED); } dasynq::rearm service_child_watcher::status_change(eventloop_t &loop, pid_t child, int status) noexcept @@ -468,7 +468,7 @@ void service_record::start(bool activate) noexcept // We're STOPPING, and that can be interrupted. Our dependencies might be STOPPING, // but if so they are waiting (for us), so they too can be instantly returned to // STARTING state. - notify_listeners(service_event::STOPCANCELLED); + notify_listeners(service_event_t::STOPCANCELLED); } else if (! was_active) { services->service_active(this); @@ -550,7 +550,7 @@ void service_record::do_start() noexcept } } -void service_record::dependencyStarted() noexcept +void service_record::dependency_started() noexcept { if ((service_state == service_state_t::STARTING || service_state == service_state_t::STARTED) && waiting_for_deps) { @@ -677,9 +677,7 @@ void service_record::all_deps_started(bool has_console) noexcept waiting_for_deps = false; - // We overload can_interrupt_start to check whether there is any other - // process (eg restart timer) that needs to finish before starting. - if (can_interrupt_start()) { + if (! can_proceed_to_start()) { waiting_for_deps = true; return; } @@ -787,7 +785,7 @@ void service_record::started() noexcept log_service_started(service_name); service_state = service_state_t::STARTED; - notify_listeners(service_event::STARTED); + notify_listeners(service_event_t::STARTED); if (onstart_flags.rw_ready) { open_control_socket(); @@ -804,7 +802,7 @@ void service_record::started() noexcept // Notify any dependents whose desired state is STARTED: for (auto dept : dependents) { - dept->get_from()->dependencyStarted(); + dept->get_from()->dependency_started(); dept->waiting_on = false; } } @@ -822,7 +820,7 @@ void service_record::failed_to_start(bool depfailed) noexcept start_explicit = false; release(); } - notify_listeners(service_event::FAILEDSTART); + notify_listeners(service_event_t::FAILEDSTART); // Cancel start of dependents: for (auto & dept : dependents) { @@ -838,7 +836,7 @@ void service_record::failed_to_start(bool depfailed) noexcept case dependency_type::SOFT: if (dept->waiting_on) { dept->waiting_on = false; - dept->get_from()->dependencyStarted(); + dept->get_from()->dependency_started(); } if (dept->holding_acq) { dept->holding_acq = false; @@ -905,7 +903,7 @@ bool base_process_service::start_ps_process(const std::vector &cmd fcntl(control_socket[0], F_SETFD, fdflags | FD_CLOEXEC); try { - control_conn = new control_conn_t(&eventLoop, services, control_socket[0]); + control_conn = new control_conn_t(eventLoop, services, control_socket[0]); } catch (std::exception &exc) { log(loglevel_t::ERROR, service_name, ": can't launch process; out of memory"); @@ -1140,7 +1138,7 @@ void service_record::do_stop() noexcept } // We must have had desired_state == STARTED. - notify_listeners(service_event::STARTCANCELLED); + notify_listeners(service_event_t::STARTCANCELLED); interrupt_start(); diff --git a/src/service.h b/src/service.h index 0422053..b4bac6b 100644 --- a/src/service.h +++ b/src/service.h @@ -103,8 +103,8 @@ */ struct onstart_flags_t { - bool rw_ready : 1; - bool log_ready : 1; + bool rw_ready : 1; // file system should be writable once this service starts + bool log_ready : 1; // syslog should be available once this service starts // Not actually "onstart" commands: bool no_sigterm : 1; // do not send SIGTERM @@ -286,25 +286,24 @@ class service_record bool pinned_stopped : 1; bool pinned_started : 1; bool waiting_for_deps : 1; // if STARTING, whether we are waiting for dependencies (inc console) to start + // if STOPPING, whether we are waiting for dependents to stop bool waiting_for_execstat : 1; // if we are waiting for exec status after fork() - bool start_explicit : 1; // whether we are are explictly required to be started + bool start_explicit : 1; // whether we are are explicitly required to be started bool prop_require : 1; // require must be propagated bool prop_release : 1; // release must be propagated bool prop_failure : 1; // failure to start must be propagated bool prop_start : 1; bool prop_stop : 1; + bool restarting : 1; // re-starting after unexpected termination int required_by = 0; // number of dependents wanting this service to be started - typedef std::list sr_list; - typedef sr_list::iterator sr_iter; - - // list of soft dependencies + // list of dependencies typedef std::list dep_list; - // list of soft dependents + // list of dependents typedef std::list dpt_list; dep_list depends_on; // services this one depends on @@ -368,7 +367,7 @@ class service_record int csfd) noexcept; // A dependency has reached STARTED state - void dependencyStarted() noexcept; + void dependency_started() noexcept; void all_deps_started(bool haveConsole = false) noexcept; @@ -391,6 +390,13 @@ class service_record return waiting_for_deps; } + // Whether a STARTING service can transition to its STARTED state, once all + // dependencies have started. + virtual bool can_proceed_to_start() noexcept + { + return true; + } + virtual void interrupt_start() noexcept; // Whether a STOPPING service can immediately transition to STARTED. @@ -419,10 +425,10 @@ class service_record || (service_state == service_state_t::STARTING && waiting_for_deps); } - void notify_listeners(service_event event) noexcept + void notify_listeners(service_event_t event) noexcept { for (auto l : listeners) { - l->serviceEvent(this, event); + l->service_event(this, event); } } @@ -662,6 +668,11 @@ class base_process_service : public service_record return waiting_restart_timer || service_record::can_interrupt_start(); } + virtual bool can_proceed_to_start() noexcept override + { + return ! waiting_restart_timer; + } + virtual void interrupt_start() noexcept override; // Kill with SIGKILL @@ -880,7 +891,7 @@ class service_set } // Get the list of all loaded services. - const std::list &listServices() + const std::list &list_services() noexcept { return records; } -- 2.25.1