static struct timeval tv_start_poweroff;
static dd_list *poweroff_options;
static struct power_option poweroff_opt;
-static bool poweroff_triggered;
-static bool poweroff_wait_timer_activated;
static dd_list *poweroff_handles;
static const char *poweroff_type_flagpaths[] = { // index denotes type
[POWEROFF_TYPE_EXIT] = POWER_EXIT,
};
+enum poweroff_stage {
+ POWEROFF_DEFAULT, /* Default stage, poweroff has not been triggered */
+ POWEROFF_TRIGGERED, /* Poweroff is triggered. Wait timer can be added up to this stage */
+ POWEROFF_WAIT_OTHERS, /* Wait for other processes to clean up their resources */
+};
+
+static enum poweroff_stage poweroff_stage;
+
static const char *poweroff_type_to_name(enum poweroff_type type)
{
if (type <= 0 || type >= ARRAY_SIZE(poweroff_type_names))
free(handle);
}
-static gboolean poweroff_timeout_cb(void *data)
+static gboolean poweroff_wait_timeout_cb(void *data)
{
char timeout[50] = {0,};
pid_t pid = (pid_t)((intptr_t)data);
poweroff_remove_handle(pid);
- if (DD_LIST_LENGTH(poweroff_handles)) {
- _D("Timer is left.");
- return G_SOURCE_REMOVE;
- }
- _D("No timer left.");
+ /* All other processes finished cleanup. Poweroff is now on standby */
+ if (poweroff_stage == POWEROFF_WAIT_OTHERS && DD_LIST_LENGTH(poweroff_handles) == 0) {
+ _D("The last poweroff wait timer for pid %d is expired. Poweroff is now on standby.", pid);
- if (!poweroff_type_to_name(poweroff_opt.type)) {
- _E("Invalid type(%d).", poweroff_opt.type);
- goto out;
- }
+ CRITICAL_LOG("Starting poweroff sequence.");
- // Watchdog timeout 90 -> 30 sec to reduce delay from unexpected poweroff failure.
- snprintf(timeout, sizeof(timeout), "WATCHDOG_USEC=%llu", (unsigned long long)POWEROFF_WAIT_SYSTEMD_MS*1000);
- sd_notify(0, timeout);
+ // Watchdog timeout 90 -> 30 sec to reduce delay from unexpected poweroff failure.
+ snprintf(timeout, sizeof(timeout), "WATCHDOG_USEC=%llu", (unsigned long long)POWEROFF_WAIT_SYSTEMD_MS*1000);
+ sd_notify(0, timeout);
- make_power_flag(poweroff_opt.type, poweroff_opt.option);
+ make_power_flag(poweroff_opt.type, poweroff_opt.option);
- if (disp_plgn.pm_lock_internal)
- disp_plgn.pm_lock_internal(INTERNAL_LOCK_POWEROFF, LCD_OFF, STAY_CUR_STATE, 0);
+ if (disp_plgn.pm_lock_internal)
+ disp_plgn.pm_lock_internal(INTERNAL_LOCK_POWEROFF, LCD_OFF, STAY_CUR_STATE, 0);
- poweroff_prepare();
- poweroff();
-out:
- if (disp_plgn.update_pm_setting)
- disp_plgn.update_pm_setting(SETTING_POWEROFF, poweroff_opt.type);
+ poweroff_prepare();
+ poweroff();
+
+ if (disp_plgn.update_pm_setting)
+ disp_plgn.update_pm_setting(SETTING_POWEROFF, poweroff_opt.type);
+ } else {
+ _D("Poweroff wait timer for pid %d is expired, but keep waiting for others...", pid);
+ }
return G_SOURCE_REMOVE;
}
bool timer_exist = false;
int pid_alive = 0;
- poweroff_wait_timer_activated = true;
+ poweroff_stage = POWEROFF_WAIT_OTHERS;
DD_LIST_FOREACH(poweroff_handles, l, handle) {
pid_alive = kill(handle->pid, 0);
_D("Run timer, pid=%d timeout=%d timeout_id=%d.", handle->pid, handle->timeout, handle->timeout_id);
handle->timeout_id = g_timeout_add_seconds(handle->timeout,
- poweroff_timeout_cb,
+ poweroff_wait_timeout_cb,
(void *)((intptr_t)(handle->pid)));
timer_exist = true;
handle->pid = getpid();
handle->timeout = 0;
handle->timeout_id = g_timeout_add_seconds(handle->timeout,
- poweroff_timeout_cb,
+ poweroff_wait_timeout_cb,
(void *)((intptr_t)(handle->pid)));
if (!handle->timeout_id) {
{
int ret;
- if (poweroff_triggered) {
- _E("During poweroff.");
+ if (poweroff_stage >= POWEROFF_TRIGGERED) {
+ _E("Duplicate poweroff request. Poweroff was already triggered.");
return -EINVAL;
}
_E("Failed to get type enum value(%d).", type_e);
return -EINVAL;
}
+
if (poweroff_option_valid(type_e, option)) {
poweroff_opt.type = type_e;
free(poweroff_opt.option);
if (ret < 0)
_E("Failed to set vconf value for power off status: %d", vconf_get_ext_errno());
- poweroff_triggered = true;
+ poweroff_stage = POWEROFF_TRIGGERED;
/* Poweroff event broadcasting */
system_shutdown_send_system_event();
if (ret < 0)
goto out;
+
CRITICAL_LOG("Poweroff PID(%d) requests %s.", ret, type_str);
ret = power_execute_pid(type_str, NULL);
if (ret < 0)
goto out;
+
CRITICAL_LOG("Poweroff PID(%d) requests type=%s option=%s.", ret, type, option);
ret = power_execute_pid(type, option);
return g_variant_new("(i)", ret);
}
+/* timer can be added before the stage POWEROFF_WAIT_OTHERS */
static GVariant *add_poweroff_time(GDBusConnection *conn,
const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
pid_t pid;
dd_list *l;
- if (poweroff_wait_timer_activated) {
- _E("It's too late. Poweroff wait timers are already activated.");
+ if (poweroff_stage >= POWEROFF_WAIT_OTHERS) {
+ _E("It's too late. Poweroff is already in waiting stage.");
ret = -1;
goto out;
}
pid = (pid_t)ret;
- CRITICAL_LOG("PID %d request poweroff timer.", pid);
+ CRITICAL_LOG("PID %d requested to a poweroff timer.", pid);
DD_LIST_FOREACH(poweroff_handles, l, handle) {
if (handle->pid == pid)
pid = (pid_t)ret;
- _D("Remove_poweroff_timer pid=%d", pid);
+ CRITICAL_LOG("PID %d requested to remove poweroff timer.", pid);
DD_LIST_FOREACH(poweroff_handles, l, handle) {
if (handle->pid == pid)
}
if (handle) {
- assert(handle);
-
- if (handle && handle->timeout_id) {
+ if (handle->timeout_id)
g_source_remove(handle->timeout_id);
- handle->timeout = 0;
- handle->timeout_id = g_timeout_add_seconds(handle->timeout,
- poweroff_timeout_cb,
- (void *)((intptr_t)(handle->pid)));
- }
+ handle->timeout = 0;
+ handle->timeout_id = g_timeout_add_seconds(handle->timeout,
+ poweroff_wait_timeout_cb,
+ (void *)((intptr_t)(handle->pid)));
} else {
_E("Invalid pid(%d).", pid);
ret = -1;
ret = config_parse(POWER_CONF_FILE, load_config, NULL);
if (ret < 0)
_E("Failed to load power off config: %d", ret);
+
+ poweroff_stage = POWEROFF_DEFAULT;
}
static const struct device_ops power_device_ops = {