chiark / gitweb /
service: introduce Type=idle and use it for gettys
[elogind.git] / src / core / transaction.c
index 398494778337b76c7163ab0286da105c36a1a60c..09ed80737d4885c945edde7f042e68eea1fd7618 100644 (file)
@@ -19,6 +19,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <unistd.h>
+#include <fcntl.h>
+
 #include "transaction.h"
 #include "bus-errors.h"
 
@@ -51,7 +54,7 @@ void transaction_abort(Transaction *tr) {
         assert(tr);
 
         while ((j = hashmap_first(tr->jobs)))
-                transaction_delete_job(tr, j, true);
+                transaction_delete_job(tr, j, false);
 
         assert(hashmap_isempty(tr->jobs));
 }
@@ -546,18 +549,16 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
 
                 /* When isolating first kill all installed jobs which
                  * aren't part of the new transaction */
-        rescan:
                 HASHMAP_FOREACH(j, m->jobs, i) {
                         assert(j->installed);
 
                         if (hashmap_get(tr->jobs, j->unit))
                                 continue;
 
-                        /* 'j' itself is safe to remove, but if other jobs
-                           are invalidated recursively, our iterator may become
-                           invalid and we need to start over. */
-                        if (job_finish_and_invalidate(j, JOB_CANCELED) > 0)
-                                goto rescan;
+                        /* Not invalidating recursively. Avoids triggering
+                         * OnFailure= actions of dependent jobs. Also avoids
+                         * invalidating our iterator. */
+                        job_finish_and_invalidate(j, JOB_CANCELED, false);
                 }
         }
 
@@ -603,6 +604,8 @@ rollback:
 }
 
 int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e) {
+        Iterator i;
+        Job *j;
         int r;
         unsigned generation = 1;
 
@@ -611,6 +614,12 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e
         /* This applies the changes recorded in tr->jobs to
          * the actual list of jobs, if possible. */
 
+        /* Reset the generation counter of all installed jobs. The detection of cycles
+         * looks at installed jobs. If they had a non-zero generation from some previous
+         * walk of the graph, the algorithm would break. */
+        HASHMAP_FOREACH(j, m->jobs, i)
+                j->generation = 0;
+
         /* First step: figure out which jobs matter */
         transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
 
@@ -687,6 +696,17 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e
 
         assert(hashmap_isempty(tr->jobs));
 
+        if (!hashmap_isempty(m->jobs)) {
+                /* Are there any jobs now? Then make sure we have the
+                 * idle pipe around. We don't really care too much
+                 * whether this works or not, as the idle pipe is a
+                 * feature for cosmetics, not actually useful for
+                 * anything beyond that. */
+
+                if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0)
+                        pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
+        }
+
         return 0;
 }