diff options
author | Lennart Poettering <lennart@poettering.net> | 2012-05-24 02:22:35 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2012-05-24 02:22:35 +0200 |
commit | e056b01d8acea7fc06d52ef91d227d744faf5259 (patch) | |
tree | ac61334a320ed5dfffcea1e08b9d0d8b9f3bac60 /src/core/service.c | |
parent | d5c446c95abf0cd8edbc55a252514bc7577dc749 (diff) |
service: for Type=idle units consider START_PRE, START, START_POST all as ACTIVE
We want to avoid a deadlock when a service has ExecStartPre= programs
that wait for the job queue to run empty because of Type=idle, but which
themselves keep the queue non-empty because START_PRE was considered
ACTIVATING and hence the job not complete. With this patch we alter the
state translation table so that it is impossible ever to wait for
Type=idle unit, hence removing the deadlock.
Diffstat (limited to 'src/core/service.c')
-rw-r--r-- | src/core/service.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/src/core/service.c b/src/core/service.c index 940d664701..936fee2636 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -108,6 +108,26 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING }; +/* For Type=idle we never want to delay any other jobs, hence we + * consider idle jobs active as soon as we start working on them */ +static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] = { + [SERVICE_DEAD] = UNIT_INACTIVE, + [SERVICE_START_PRE] = UNIT_ACTIVE, + [SERVICE_START] = UNIT_ACTIVE, + [SERVICE_START_POST] = UNIT_ACTIVE, + [SERVICE_RUNNING] = UNIT_ACTIVE, + [SERVICE_EXITED] = UNIT_ACTIVE, + [SERVICE_RELOAD] = UNIT_RELOADING, + [SERVICE_STOP] = UNIT_DEACTIVATING, + [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING, + [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING, + [SERVICE_STOP_POST] = UNIT_DEACTIVATING, + [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING, + [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING, + [SERVICE_FAILED] = UNIT_FAILED, + [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING +}; + static void service_init(Unit *u) { Service *s = SERVICE(u); int i; @@ -1471,8 +1491,11 @@ static void service_notify_sockets_dead(Service *s, bool failed_permanent) { static void service_set_state(Service *s, ServiceState state) { ServiceState old_state; + const UnitActiveState *table; assert(s); + table = s->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table; + old_state = s->state; s->state = state; @@ -1555,7 +1578,7 @@ static void service_set_state(Service *s, ServiceState state) { if (old_state != state) log_debug("%s changed %s -> %s", UNIT(s)->id, service_state_to_string(old_state), service_state_to_string(state)); - unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], s->reload_result == SERVICE_SUCCESS); + unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS); s->reload_result = SERVICE_SUCCESS; } @@ -2694,9 +2717,13 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, } static UnitActiveState service_active_state(Unit *u) { + const UnitActiveState *table; + assert(u); - return state_translation_table[SERVICE(u)->state]; + table = SERVICE(u)->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table; + + return table[SERVICE(u)->state]; } static const char *service_sub_state_to_string(Unit *u) { |