}
}
-void ServiceRecord::start() noexcept
+void ServiceRecord::start(bool unpinned) noexcept
{
if ((service_state == ServiceState::STARTING || service_state == ServiceState::STARTED)
&& desired_state == ServiceState::STOPPED) {
// its cancellation
}
- if (desired_state == ServiceState::STARTED) return;
+ if (desired_state == ServiceState::STARTED && !unpinned) return;
desired_state = ServiceState::STARTED;
return;
}
+ if (pinned_stopped) return;
+
service_state = ServiceState::STARTING;
service_set->service_active(this);
}
}
-void ServiceRecord::stop() noexcept
+void ServiceRecord::stop(bool unpinned) noexcept
{
if ((service_state == ServiceState::STOPPING || service_state == ServiceState::STOPPED)
&& desired_state == ServiceState::STARTED) {
// TODO inform listeners waiting for start of cancellation
}
- if (desired_state == ServiceState::STOPPED) return;
+ if (desired_state == ServiceState::STOPPED && !unpinned) return;
desired_state = ServiceState::STOPPED;
+
+ if (pinned_started) return;
if (service_state != ServiceState::STARTED) {
if (service_state == ServiceState::STARTING) {
}
}
+void ServiceRecord::pinStart() noexcept
+{
+ pinned_stopped = false;
+ start();
+ pinned_started = true;
+}
+
+void ServiceRecord::pinStop() noexcept
+{
+ pinned_started = false;
+ stop();
+ pinned_stopped = true;
+}
+
+void ServiceRecord::unpin() noexcept
+{
+ if (pinned_started) {
+ pinned_started = false;
+ if (desired_state == ServiceState::STOPPED) {
+ stop(true);
+ }
+ }
+ if (pinned_stopped) {
+ pinned_stopped = false;
+ if (desired_state == ServiceState::STARTED) {
+ start(true);
+ }
+ }
+}
+
void ServiceSet::service_active(ServiceRecord *sr) noexcept
{
active_services++;
*
* Services have both a current state and a desired state. The desired state can be
* either STARTED or STOPPED. The current state can also be STARTING or STOPPING.
+ * A service can be "pinned" in either the STARTED or STOPPED states to prevent it
+ * from leaving that state until it is unpinned.
*
* The total state is a combination of the two, current and desired:
* STOPPED/STOPPED : stopped and will remain stopped
- * STOPPED/STARTED : - (this state cannot occur)
+ * STOPPED/STARTED : stopped (pinned), must be unpinned to start
* STARTING/STARTED : starting, but not yet started. Dependencies may also be starting.
* STARTING/STOPPED : as above, but the service will be stopped again as soon as it has
* completed startup.
* STARTED/STARTED : running and will continue running.
- * STARTED/STOPPED : - (this state cannot occur)
+ * STARTED/STOPPED : started (pinned), must be unpinned to stop
* STOPPING/STOPPED : stopping and will stop. Dependents may be stopping.
* STOPPING/STARTED : as above, but the service will be re-started again once it stops.
*
OnstartFlags onstart_flags;
string logfile; /* log file name, empty string specifies /dev/null */
- bool auto_restart; /* whether to restart this (process) if it dies unexpectedly */
-
+ bool auto_restart : 1; /* whether to restart this (process) if it dies unexpectedly */
+ bool pinned_stopped : 1;
+ bool pinned_started : 1;
typedef std::list<ServiceRecord *> sr_list;
typedef sr_list::iterator sr_iter;
public:
ServiceRecord(ServiceSet *set, string name)
- : service_state(ServiceState::STOPPED), desired_state(ServiceState::STOPPED), auto_restart(false), force_stop(false)
+ : service_state(ServiceState::STOPPED), desired_state(ServiceState::STOPPED), auto_restart(false),
+ pinned_stopped(false), pinned_started(false), force_stop(false)
{
service_set = set;
service_name = name;
ServiceRecord(ServiceSet *set, string name, ServiceType service_type, string &&command, std::list<std::pair<unsigned,unsigned>> &command_offsets,
sr_list * pdepends_on, sr_list * pdepends_soft)
- : service_state(ServiceState::STOPPED), desired_state(ServiceState::STOPPED), auto_restart(false), force_stop(false)
+ : ServiceRecord(set, name)
{
service_set = set;
service_name = name;
const char *getServiceName() const noexcept { return service_name.c_str(); }
ServiceState getState() const noexcept { return service_state; }
- void start() noexcept; // start the service
- void stop() noexcept; // stop the service
+ void start(bool unpinned = false) noexcept; // start the service
+ void stop(bool unpinned = false) noexcept; // stop the service
+
+ void pinStart() noexcept; // start the service and pin it
+ void pinStop() noexcept; // stop the service and pin it
+ void unpin() noexcept; // unpin the service
bool isDummy() noexcept
{