power: introduce transient state 72/285072/3
authorYoungjae Cho <y0.cho@samsung.com>
Tue, 22 Nov 2022 08:27:36 +0000 (17:27 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Thu, 8 Dec 2022 02:30:10 +0000 (11:30 +0900)
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 <y0.cho@samsung.com>
src/power/power.c
src/power/power.h

index 0ae9be6..e44b7ed 100644 (file)
@@ -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);
 }
index 3f469f8..7771556 100644 (file)
@@ -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";