summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/execute.c11
-rw-r--r--src/core/execute.h1
-rw-r--r--src/core/manager.c10
-rw-r--r--src/core/manager.h3
-rw-r--r--src/core/mount.c1
-rw-r--r--src/core/service.c6
-rw-r--r--src/core/service.h1
-rw-r--r--src/core/socket.c1
-rw-r--r--src/core/swap.c1
-rw-r--r--src/core/transaction.c14
10 files changed, 45 insertions, 4 deletions
diff --git a/src/core/execute.c b/src/core/execute.c
index c59f7e2daa..99a7881f1c 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -37,6 +37,7 @@
#include <sys/mount.h>
#include <linux/fs.h>
#include <linux/oom.h>
+#include <sys/poll.h>
#ifdef HAVE_PAM
#include <security/pam_appl.h>
@@ -963,6 +964,7 @@ int exec_spawn(ExecCommand *command,
CGroupBonding *cgroup_bondings,
CGroupAttribute *cgroup_attributes,
const char *cgroup_suffix,
+ int idle_pipe[2],
pid_t *ret) {
pid_t pid;
@@ -1050,6 +1052,15 @@ int exec_spawn(ExecCommand *command,
goto fail_child;
}
+ if (idle_pipe) {
+ if (idle_pipe[1] >= 0)
+ close_nointr_nofail(idle_pipe[1]);
+ if (idle_pipe[0] >= 0) {
+ fd_wait_for_event(idle_pipe[0], POLLHUP, DEFAULT_TIMEOUT_USEC);
+ close_nointr_nofail(idle_pipe[0]);
+ }
+ }
+
/* Close sockets very early to make sure we don't
* block init reexecution because it cannot bind its
* sockets */
diff --git a/src/core/execute.h b/src/core/execute.h
index 428bb7c9bf..03c63d465a 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -193,6 +193,7 @@ int exec_spawn(ExecCommand *command,
struct CGroupBonding *cgroup_bondings,
struct CGroupAttribute *cgroup_attributes,
const char *cgroup_suffix,
+ int pipe_fd[2],
pid_t *ret);
void exec_command_done(ExecCommand *c);
diff --git a/src/core/manager.c b/src/core/manager.c
index f7ccba6235..a6013668b8 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -259,6 +259,7 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
m->exit_code = _MANAGER_EXIT_CODE_INVALID;
m->pin_cgroupfs_fd = -1;
+ m->idle_pipe[0] = m->idle_pipe[1] = -1;
#ifdef HAVE_AUDIT
m->audit_fd = -1;
@@ -518,6 +519,8 @@ void manager_free(Manager *m) {
hashmap_free(m->cgroup_bondings);
set_free_free(m->unit_path_cache);
+ close_pipe(m->idle_pipe);
+
free(m);
}
@@ -1962,10 +1965,13 @@ void manager_check_finished(Manager *m) {
assert(m);
- if (dual_timestamp_is_set(&m->finish_timestamp))
+ if (hashmap_size(m->jobs) > 0)
return;
- if (hashmap_size(m->jobs) > 0)
+ /* Notify Type=idle units that we are done now */
+ close_pipe(m->idle_pipe);
+
+ if (dual_timestamp_is_set(&m->finish_timestamp))
return;
dual_timestamp_get(&m->finish_timestamp);
diff --git a/src/core/manager.h b/src/core/manager.h
index 808a0d4286..154c1faeb7 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -227,6 +227,9 @@ struct Manager {
unsigned n_installed_jobs;
unsigned n_failed_jobs;
+
+ /* Type=idle pipes */
+ int idle_pipe[2];
};
int manager_new(ManagerRunningAs running_as, Manager **m);
diff --git a/src/core/mount.c b/src/core/mount.c
index e662af0c87..3357b7df5b 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -801,6 +801,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
UNIT(m)->cgroup_bondings,
UNIT(m)->cgroup_attributes,
NULL,
+ NULL,
&pid)) < 0)
goto fail;
diff --git a/src/core/service.c b/src/core/service.c
index 59dd71294b..4358a948de 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1769,6 +1769,7 @@ static int service_spawn(
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
is_control ? "control" : NULL,
+ s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
&pid);
if (r < 0)
@@ -2130,7 +2131,7 @@ static void service_enter_start(Service *s) {
if (r < 0)
goto fail;
- if (s->type == SERVICE_SIMPLE) {
+ if (s->type == SERVICE_SIMPLE || s->type == SERVICE_IDLE) {
/* For simple services we immediately start
* the START_POST binaries. */
@@ -3714,7 +3715,8 @@ static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
[SERVICE_FORKING] = "forking",
[SERVICE_ONESHOT] = "oneshot",
[SERVICE_DBUS] = "dbus",
- [SERVICE_NOTIFY] = "notify"
+ [SERVICE_NOTIFY] = "notify",
+ [SERVICE_IDLE] = "idle"
};
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
diff --git a/src/core/service.h b/src/core/service.h
index eb41314931..819672f617 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -65,6 +65,7 @@ typedef enum ServiceType {
SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */
+ SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */
_SERVICE_TYPE_MAX,
_SERVICE_TYPE_INVALID = -1
} ServiceType;
diff --git a/src/core/socket.c b/src/core/socket.c
index 31aff5bcec..1d56829baf 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1152,6 +1152,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
NULL,
+ NULL,
&pid);
strv_free(argv);
diff --git a/src/core/swap.c b/src/core/swap.c
index 9c30c11bb4..fea3f6887a 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -620,6 +620,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
NULL,
+ NULL,
&pid)) < 0)
goto fail;
diff --git a/src/core/transaction.c b/src/core/transaction.c
index aee155f519..09ed80737d 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -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"
@@ -693,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;
}