#include <set>
#include <algorithm>
#include <memory>
+#include <mutex>
+#include <condition_variable>
+#include <list>
#include <fcntl.h>
#include <signal.h>
"com.samsung.factoryreset.start.setting"
};
+
+// watches systemd jobs
+class JobWatch {
+public:
+ explicit JobWatch(dbus::Connection& systemDBus);
+ ~JobWatch();
+
+ bool waitForJob(const std::string& job);
+
+private:
+ void jobRemoved(const dbus::Variant& parameters);
+
+ struct Job {
+ Job(uint32_t id,
+ const std::string& job,
+ const std::string& unit,
+ const std::string& result) : id(id), job(job), unit(unit), result(result) {}
+ uint32_t id;
+ std::string job;
+ std::string unit;
+ std::string result;
+ };
+
+ dbus::Connection::SubscriptionId id;
+ dbus::Connection& systemDBus;
+ std::list<Job> removedJobs;
+ std::mutex jobsMutex;
+ std::condition_variable jobsCv;
+};
+
+JobWatch::JobWatch(dbus::Connection& systemDBus) : systemDBus(systemDBus) {
+ auto callback = [this](dbus::Variant parameters) {
+ this->jobRemoved(parameters);
+ };
+
+ id = systemDBus.subscribeSignal("",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "JobRemoved",
+ callback);
+}
+
+JobWatch::~JobWatch() {
+ systemDBus.unsubscribeSignal(id);
+}
+
+bool JobWatch::waitForJob(const std::string& job) {
+ while(true) {
+ std::unique_lock<std::mutex> lock(jobsMutex);
+ jobsCv.wait(lock, [this]{ return !removedJobs.empty(); });
+
+ while(!removedJobs.empty()) {
+ bool match = (removedJobs.front().job == job);
+ bool done = (removedJobs.front().result == "done");
+ removedJobs.pop_front();
+ if (match)
+ return done;
+ }
+ };
+}
+
+void JobWatch::jobRemoved(const dbus::Variant& parameters)
+{
+ uint32_t id;
+ const char* job;
+ const char* unit;
+ const char* result;
+ parameters.get("(uoss)", &id, &job, &unit, &result);
+ INFO(SINK, "id:" + std::to_string(id) + " job:" + job + " unit:" + unit + " result:" + result);
+
+ {
+ std::lock_guard<std::mutex> guard(jobsMutex);
+ removedJobs.emplace_back(id, job, unit, result);
+ }
+ jobsCv.notify_one();
+}
+
void stopKnownSystemdUnits()
{
std::vector<std::string> knownSystemdUnits;
}
}
+ JobWatch watch(systemDBus);
+
for (const std::string& unit : knownSystemdUnits) {
INFO(SINK, "Stopping unit: " + unit);
+ const char* job = NULL;
systemDBus.methodcall("org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StopUnit",
- -1, "", "(ss)", unit.c_str(), "flush");
+ -1, "(o)", "(ss)", unit.c_str(), "flush").get("(o)", &job);
+ INFO(SINK, "Waiting for job: " + std::string(job));
+ if (!watch.waitForJob(job))
+ throw runtime::Exception("Stopping unit: " + unit + " failed");
}
-
- sleep(1); // TODO wait for confirmation from systemd instead
}
void stopDependedSystemdUnits()
}
}
+ JobWatch watch(systemDBus);
+
for (const std::string& unit : unitsToStop) {
INFO(SINK, "Stopping unit: " + unit);
+ const char* job = NULL;
systemDBus.methodcall("org.freedesktop.systemd1",
unit,
"org.freedesktop.systemd1.Unit",
"Stop",
- -1, "", "(s)", "flush");
+ -1, "(o)", "(s)", "flush").get("(o)", &job);
+ INFO(SINK, "Waiting for job: " + std::string(job));
+ if (!watch.waitForJob(job))
+ throw runtime::Exception("Stopping unit: " + unit + " failed");
}
}