From cad6af15712aff4e5b4ad5a412a997ca69b697fc Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Tue, 22 Nov 2022 17:27:36 +0900 Subject: [PATCH] power: introduce transient state It is able to define transient state between static states. The deviced always follows those transient states in sequence. It provides some checkpoints between static states, giving chances for other processes to sync with each other. Change-Id: I446083fd1c90610f805a64d61f16defc5a0a9b67 Signed-off-by: Youngjae Cho (cherry picked from commit 888dc040d3e1b48d7d370919292ccf2a0646562c) --- src/power/power.c | 130 ++++++++++++++++++++++++++++++++++++++++++++---------- src/power/power.h | 12 +++++ 2 files changed, 119 insertions(+), 23 deletions(-) diff --git a/src/power/power.c b/src/power/power.c index 0ae9be6..e44b7ed 100644 --- a/src/power/power.c +++ b/src/power/power.c @@ -50,6 +50,7 @@ static struct { int ongoing; struct trans_info ti; GList *waitings; + int transient_step; int max_wait_timer; } transition_context; @@ -66,9 +67,36 @@ struct change_state_wait { int state; }; +static const uint64_t transient_scenario_suspending[] = { + POWER_STATE_TRANSIENT_SUSPENDING_EARLY, + POWER_STATE_TRANSIENT_SUSPENDING, + POWER_STATE_TRANSIENT_SUSPENDING_LATE, +}; + +static const uint64_t transient_scenario_resuming[] = { + POWER_STATE_TRANSIENT_RESUMING_EARLY, + POWER_STATE_TRANSIENT_RESUMING, + POWER_STATE_TRANSIENT_RESUMING_LATE, +}; + +static const struct { + int max_step; + const uint64_t *scenario; +} transient[POWER_STATE_MAX_INDEX][POWER_STATE_MAX_INDEX] = { + [POWER_STATE_NORMAL_INDEX][POWER_STATE_SLEEP_INDEX] = { + .max_step = ARRAY_SIZE(transient_scenario_suspending), + .scenario = transient_scenario_suspending, + }, + [POWER_STATE_SLEEP_INDEX][POWER_STATE_NORMAL_INDEX] = { + .max_step = ARRAY_SIZE(transient_scenario_resuming), + .scenario = transient_scenario_resuming, + }, +}; + static int transition_request_callback(void *data); static void prepare_transition(const struct trans_info *ti); static void action_transition(void); +static uint64_t get_next_state(void); static void power_action_normal(void *data); static void power_action_sleep(void *data); @@ -255,25 +283,39 @@ static void broadcast_transition_info(void) { const char *signame; - if (transition_context.ti.next == POWER_STATE_START) + uint64_t next = get_next_state(); + + if (next == POWER_STATE_START) signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_START; - else if (transition_context.ti.next == POWER_STATE_NORMAL) + else if (next == POWER_STATE_NORMAL) signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_NORMAL; - else if (transition_context.ti.next == POWER_STATE_SLEEP) + else if (next == POWER_STATE_SLEEP) signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SLEEP; - else if (transition_context.ti.next == POWER_STATE_POWEROFF) + else if (next == POWER_STATE_POWEROFF) signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_POWEROFF; - else if (transition_context.ti.next == POWER_STATE_REBOOT) + else if (next == POWER_STATE_REBOOT) signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_REBOOT; - else if (transition_context.ti.next == POWER_STATE_EXIT) + else if (next == POWER_STATE_EXIT) signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_EXIT; + else if (next == POWER_STATE_TRANSIENT_SUSPENDING_EARLY) + signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_EARLY; + else if (next == POWER_STATE_TRANSIENT_SUSPENDING) + signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING; + else if (next == POWER_STATE_TRANSIENT_SUSPENDING_LATE) + signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_LATE; + else if (next == POWER_STATE_TRANSIENT_RESUMING_EARLY) + signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_EARLY; + else if (next == POWER_STATE_TRANSIENT_RESUMING) + signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING; + else if (next == POWER_STATE_TRANSIENT_RESUMING_LATE) + signame = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_LATE; else return; gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, signame, g_variant_new("(ttti)", transition_context.ti.curr, - transition_context.ti.next, + next, transition_context.id, transition_context.ti.reason)); } @@ -330,13 +372,27 @@ static void enqueue_transition(const struct trans_info *ti) g_queue_push_head(transition_queue, memcpy(ti_new, ti, sizeof(struct trans_info))); } +// intermediate state of ongoing transition +// it might be a transient state or a destination state +static uint64_t get_next_state(void) +{ + int curr = POWER_STATE_INDEX(transition_context.ti.curr); + int next = POWER_STATE_INDEX(transition_context.ti.next); + int step = transition_context.transient_step; + + if (step >= transient[curr][next].max_step) + return transition_context.ti.next; + else + return transient[curr][next].scenario[step]; +} + static void init_waiting_list(gpointer data, gpointer udata) { uint64_t waiting_state; struct proc_info *pi = (struct proc_info *) data; struct change_state_wait *csw = NULL; - waiting_state = transition_context.ti.next; + waiting_state = get_next_state(); if ((pi->state_bitmap & waiting_state) == 0) return; @@ -370,6 +426,18 @@ static char *state_abbr_name(uint64_t state) return "REBOOT"; if (state == POWER_STATE_EXIT) return "EXIT"; + if (state == POWER_STATE_TRANSIENT_SUSPENDING_EARLY) + return "SUSPENDING_EARLY"; + if (state == POWER_STATE_TRANSIENT_SUSPENDING) + return "SUSPENDING"; + if (state == POWER_STATE_TRANSIENT_SUSPENDING_LATE) + return "SUSPENDING_LATE"; + if (state == POWER_STATE_TRANSIENT_RESUMING_EARLY) + return "RESUMING_EARLY"; + if (state == POWER_STATE_TRANSIENT_RESUMING) + return "RESUMING"; + if (state == POWER_STATE_TRANSIENT_RESUMING_LATE) + return "RESUMING_LATE"; return "INVALID"; } @@ -377,10 +445,16 @@ static char *state_abbr_name(uint64_t state) static void reload_transition_sequence(GList **sequence) { GList *new_sequence = NULL; + int curr, next, step; g_list_free(g_steal_pointer(sequence)); + curr = POWER_STATE_INDEX(transition_context.ti.curr); + next = POWER_STATE_INDEX(transition_context.ti.next); + new_sequence = g_list_append(new_sequence, state_abbr_name(transition_context.ti.curr)); + for (step = 0; step < transient[curr][next].max_step; ++step) + new_sequence = g_list_append(new_sequence, state_abbr_name(transient[curr][next].scenario[step])); new_sequence = g_list_append(new_sequence, state_abbr_name(transition_context.ti.next)); *sequence = new_sequence; @@ -471,24 +545,33 @@ static void trigger_transition(void) static void action_transition(void) { - struct trans_info ti = { 0 , }; - int retval; + uint64_t state = get_next_state(); transition_description(0); - current = transition_context.ti.next; - - if (action_on_state[POWER_STATE_INDEX(current)]) - action_on_state[POWER_STATE_INDEX(current)](transition_context.ti.data); - - // transition end - transition_context.ongoing = 0; - event_wake_unlock(EL_POWER_TRANSITION_STATE); - - // trigger next transition if exist - retval = dequeue_transition(&ti); - if (retval == 0) { - prepare_transition(&ti); + if (state == transition_context.ti.next) { + // it has reached the destination state + struct trans_info ti = { 0 , }; + int retval; + + current = transition_context.ti.next; + + if (action_on_state[POWER_STATE_INDEX(current)]) + action_on_state[POWER_STATE_INDEX(current)](transition_context.ti.data); + + // transition end + transition_context.ongoing = 0; + event_wake_unlock(EL_POWER_TRANSITION_STATE); + + // trigger next transition if exist + retval = dequeue_transition(&ti); + if (retval == 0) { + prepare_transition(&ti); + trigger_transition(); + } + } else { + // step into the next transient state + ++transition_context.transient_step; trigger_transition(); } } @@ -508,6 +591,7 @@ static void prepare_transition(const struct trans_info *ti) } transition_context.ongoing = 0; + transition_context.transient_step = 0; transition_description(1); } diff --git a/src/power/power.h b/src/power/power.h index 3f469f8..7771556 100644 --- a/src/power/power.h +++ b/src/power/power.h @@ -74,6 +74,18 @@ static inline const char *state_name(uint64_t state) return "POWER_STATE_REBOOT"; if (state == POWER_STATE_EXIT) return "POWER_STATE_EXIT"; + if (state == POWER_STATE_TRANSIENT_SUSPENDING_EARLY) + return "POWER_STATE_TRANSIENT_SUSPENDING_EARLY"; + if (state == POWER_STATE_TRANSIENT_SUSPENDING) + return "POWER_STATE_TRANSIENT_SUSPENDING"; + if (state == POWER_STATE_TRANSIENT_SUSPENDING_LATE) + return "POWER_STATE_TRANSIENT_SUSPENDING_LATE"; + if (state == POWER_STATE_TRANSIENT_RESUMING_EARLY) + return "POWER_STATE_TRANSIENT_RESUMING_EARLY"; + if (state == POWER_STATE_TRANSIENT_RESUMING) + return "POWER_STATE_TRANSIENT_RESUMING"; + if (state == POWER_STATE_TRANSIENT_RESUMING_LATE) + return "POWER_STATE_TRANSIENT_RESUMING_LATE"; if (state == POWER_STATE_ALL) return "POWER_STATE_ALL"; -- 2.7.4