diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/execute.c | 11 | ||||
-rw-r--r-- | src/core/execute.h | 1 | ||||
-rw-r--r-- | src/core/manager.c | 10 | ||||
-rw-r--r-- | src/core/manager.h | 3 | ||||
-rw-r--r-- | src/core/mount.c | 1 | ||||
-rw-r--r-- | src/core/service.c | 6 | ||||
-rw-r--r-- | src/core/service.h | 1 | ||||
-rw-r--r-- | src/core/socket.c | 1 | ||||
-rw-r--r-- | src/core/swap.c | 1 | ||||
-rw-r--r-- | src/core/transaction.c | 14 |
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; } |