forked from enlightenment/enlightenment
add new powersave features for supporting a live sleep mode
so new laptops now seem to no longer support S3 sleep. sleeping is done basically by going as idle as possible. you can ask the kernel to freeze execution BUT this seems to use about the same power as staying alive in my tests. to support this add 2 things: 1. a FREEZE powersave mode which implies we're alive but want to really stay as idle as absolutely possible. 2. powersave aware sleep functions that replace the usleeps in threads so they can switch from being super sleepy when in freeze mode to normal.
This commit is contained in:
parent
b88059b91a
commit
7caf5c8ff4
|
@ -8,9 +8,12 @@ struct _E_Powersave_Deferred_Action
|
|||
};
|
||||
|
||||
/* local subsystem functions */
|
||||
static void _e_powersave_sleeper_cb_dummy(void *data EINA_UNUSED, void *buffer EINA_UNUSED, unsigned int bytes EINA_UNUSED);
|
||||
static Eina_Bool _e_powersave_cb_deferred_timer(void *data);
|
||||
static void _e_powersave_mode_eval(void);
|
||||
static void _e_powersave_event_update_free(void *data EINA_UNUSED, void *event);
|
||||
static void _e_powersave_event_change_send(E_Powersave_Mode mode);
|
||||
static void _e_powersave_sleepers_wake(void);
|
||||
|
||||
/* local subsystem globals */
|
||||
E_API int E_EVENT_POWERSAVE_UPDATE = 0;
|
||||
|
@ -19,7 +22,10 @@ static int walking_deferred_actions = 0;
|
|||
static Eina_List *deferred_actions = NULL;
|
||||
static Ecore_Timer *deferred_timer = NULL;
|
||||
static E_Powersave_Mode powersave_mode = E_POWERSAVE_MODE_LOW;
|
||||
static E_Powersave_Mode powersave_mode_force = E_POWERSAVE_MODE_NONE;
|
||||
static double defer_time = 5.0;
|
||||
static Eina_Bool powersave_force = EINA_FALSE;
|
||||
static Eina_List *powersave_sleepers = NULL;
|
||||
|
||||
/* externally accessible functions */
|
||||
EINTERN int
|
||||
|
@ -46,8 +52,8 @@ e_powersave_deferred_action_add(void (*func)(void *data), const void *data)
|
|||
if (!pa) return NULL;
|
||||
if (deferred_timer) ecore_timer_del(deferred_timer);
|
||||
deferred_timer = ecore_timer_loop_add(defer_time,
|
||||
_e_powersave_cb_deferred_timer,
|
||||
NULL);
|
||||
_e_powersave_cb_deferred_timer,
|
||||
NULL);
|
||||
pa->func = func;
|
||||
pa->data = data;
|
||||
deferred_actions = eina_list_append(deferred_actions, pa);
|
||||
|
@ -80,41 +86,101 @@ e_powersave_deferred_action_del(E_Powersave_Deferred_Action *pa)
|
|||
E_API void
|
||||
e_powersave_mode_set(E_Powersave_Mode mode)
|
||||
{
|
||||
E_Event_Powersave_Update *ev;
|
||||
|
||||
if (mode < e_config->powersave.min) mode = e_config->powersave.min;
|
||||
else if (mode > e_config->powersave.max)
|
||||
mode = e_config->powersave.max;
|
||||
else if (mode > e_config->powersave.max) mode = e_config->powersave.max;
|
||||
|
||||
if (powersave_mode == mode) return;
|
||||
printf("CHANGE PW SAVE MODE TO %i / %i\n", (int)mode, E_POWERSAVE_MODE_EXTREME);
|
||||
powersave_mode = mode;
|
||||
|
||||
ev = E_NEW(E_Event_Powersave_Update, 1);
|
||||
ev->mode = mode;
|
||||
ecore_event_add(E_EVENT_POWERSAVE_UPDATE, ev, _e_powersave_event_update_free, NULL);
|
||||
if (powersave_force) return;
|
||||
_e_powersave_event_change_send(powersave_mode);
|
||||
_e_powersave_mode_eval();
|
||||
}
|
||||
|
||||
E_API E_Powersave_Mode
|
||||
e_powersave_mode_get(void)
|
||||
{
|
||||
if (powersave_force) return powersave_mode_force;
|
||||
return powersave_mode;
|
||||
}
|
||||
|
||||
E_API E_Powersave_Mode
|
||||
e_powersave_mode_min_get(void)
|
||||
E_API void
|
||||
e_powersave_mode_force(E_Powersave_Mode mode)
|
||||
{
|
||||
return e_config->powersave.min;
|
||||
if (mode == powersave_mode_force) return;
|
||||
powersave_force = EINA_TRUE;
|
||||
powersave_mode_force = mode;
|
||||
_e_powersave_event_change_send(powersave_mode_force);
|
||||
_e_powersave_mode_eval();
|
||||
}
|
||||
|
||||
E_API E_Powersave_Mode
|
||||
e_powersave_mode_max_get(void)
|
||||
E_API void
|
||||
e_powersave_mode_unforce(void)
|
||||
{
|
||||
return e_config->powersave.max;
|
||||
if (!powersave_force) return;
|
||||
powersave_force = EINA_FALSE;
|
||||
if (powersave_mode_force != powersave_mode)
|
||||
{
|
||||
_e_powersave_event_change_send(powersave_mode);
|
||||
_e_powersave_mode_eval();
|
||||
}
|
||||
powersave_mode_force = E_POWERSAVE_MODE_NONE;
|
||||
}
|
||||
|
||||
E_API E_Powersave_Sleeper *
|
||||
e_powersave_sleeper_new(void)
|
||||
{
|
||||
Ecore_Pipe *pipe;
|
||||
|
||||
pipe = ecore_pipe_add(_e_powersave_sleeper_cb_dummy, NULL);
|
||||
powersave_sleepers = eina_list_append(powersave_sleepers, pipe);
|
||||
return (E_Powersave_Sleeper *)pipe;
|
||||
}
|
||||
|
||||
E_API void
|
||||
e_powersave_sleeper_free(E_Powersave_Sleeper *sleeper)
|
||||
{
|
||||
Ecore_Pipe *pipe = (Ecore_Pipe *)sleeper;
|
||||
|
||||
if (!pipe) return;
|
||||
powersave_sleepers = eina_list_remove(powersave_sleepers, pipe);
|
||||
ecore_pipe_del(pipe);
|
||||
}
|
||||
|
||||
E_API void
|
||||
e_powersave_sleeper_sleep(E_Powersave_Sleeper *sleeper, int poll_interval)
|
||||
{
|
||||
Ecore_Pipe *pipe = (Ecore_Pipe *)sleeper;
|
||||
double tim, now;
|
||||
|
||||
if (!pipe) return;
|
||||
if (e_powersave_mode_get() == E_POWERSAVE_MODE_FREEZE) tim = 3600;
|
||||
else tim = (double)poll_interval / 8.0;
|
||||
now = ecore_time_get();
|
||||
tim = fmod(now, tim);
|
||||
ecore_pipe_wait(pipe, 1, tim);
|
||||
}
|
||||
|
||||
/* local subsystem functions */
|
||||
|
||||
static void
|
||||
_e_powersave_sleepers_wake(void)
|
||||
{
|
||||
Ecore_Pipe *pipe;
|
||||
Eina_List *l;
|
||||
char buf[1] = { 1 };
|
||||
|
||||
EINA_LIST_FOREACH(powersave_sleepers, l, pipe)
|
||||
{
|
||||
ecore_pipe_write(pipe, buf, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_e_powersave_sleeper_cb_dummy(void *data EINA_UNUSED, void *buffer EINA_UNUSED, unsigned int bytes EINA_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_e_powersave_cb_deferred_timer(void *data EINA_UNUSED)
|
||||
{
|
||||
|
@ -135,8 +201,12 @@ static void
|
|||
_e_powersave_mode_eval(void)
|
||||
{
|
||||
double t = 0.0;
|
||||
E_Powersave_Mode mode;
|
||||
|
||||
switch (powersave_mode)
|
||||
if (powersave_force) mode = powersave_mode_force;
|
||||
else mode = powersave_mode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case E_POWERSAVE_MODE_NONE:
|
||||
t = e_config->powersave.none; /* time to defer "power expensive" activities */
|
||||
|
@ -158,6 +228,10 @@ _e_powersave_mode_eval(void)
|
|||
t = e_config->powersave.extreme;
|
||||
break;
|
||||
|
||||
case E_POWERSAVE_MODE_FREEZE:
|
||||
t = 3600;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
|
@ -166,8 +240,8 @@ _e_powersave_mode_eval(void)
|
|||
{
|
||||
if (deferred_timer) ecore_timer_del(deferred_timer);
|
||||
deferred_timer = ecore_timer_loop_add(defer_time,
|
||||
_e_powersave_cb_deferred_timer,
|
||||
NULL);
|
||||
_e_powersave_cb_deferred_timer,
|
||||
NULL);
|
||||
defer_time = t;
|
||||
}
|
||||
}
|
||||
|
@ -178,3 +252,15 @@ _e_powersave_event_update_free(void *data EINA_UNUSED, void *event)
|
|||
free(event);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_powersave_event_change_send(E_Powersave_Mode mode)
|
||||
{
|
||||
E_Event_Powersave_Update *ev;
|
||||
|
||||
printf("CHANGE PW SAVE MODE TO %i / %i\n",
|
||||
(int)mode, E_POWERSAVE_MODE_EXTREME);
|
||||
ev = E_NEW(E_Event_Powersave_Update, 1);
|
||||
ev->mode = mode;
|
||||
ecore_event_add(E_EVENT_POWERSAVE_UPDATE, ev, _e_powersave_event_update_free, NULL);
|
||||
_e_powersave_sleepers_wake();
|
||||
}
|
||||
|
|
|
@ -6,11 +6,13 @@ typedef enum _E_Powersave_Mode
|
|||
E_POWERSAVE_MODE_LOW,
|
||||
E_POWERSAVE_MODE_MEDIUM,
|
||||
E_POWERSAVE_MODE_HIGH,
|
||||
E_POWERSAVE_MODE_EXTREME
|
||||
E_POWERSAVE_MODE_EXTREME,
|
||||
E_POWERSAVE_MODE_FREEZE
|
||||
} E_Powersave_Mode;
|
||||
|
||||
typedef struct _E_Powersave_Deferred_Action E_Powersave_Deferred_Action;
|
||||
typedef struct _E_Event_Powersave_Update E_Event_Powersave_Update;
|
||||
typedef struct _E_Powersave_Sleeper E_Powersave_Sleeper;
|
||||
|
||||
#else
|
||||
#ifndef E_POWERSAVE_H
|
||||
|
@ -31,6 +33,12 @@ E_API E_Powersave_Deferred_Action *e_powersave_deferred_action_add(void (*func)
|
|||
E_API void e_powersave_deferred_action_del(E_Powersave_Deferred_Action *pa);
|
||||
E_API void e_powersave_mode_set(E_Powersave_Mode mode);
|
||||
E_API E_Powersave_Mode e_powersave_mode_get(void);
|
||||
E_API void e_powersave_mode_force(E_Powersave_Mode mode);
|
||||
E_API void e_powersave_mode_unforce(void);
|
||||
E_API E_Powersave_Sleeper *e_powersave_sleeper_new(void);
|
||||
E_API void e_powersave_sleeper_free(E_Powersave_Sleeper *sleeper);
|
||||
// the below function is INTENDED to be called from a thread
|
||||
E_API void e_powersave_sleeper_sleep(E_Powersave_Sleeper *sleeper, int poll_interval);
|
||||
|
||||
/* FIXME: in the powersave system add things like pre-loading entire files
|
||||
* int memory for pre-caching to avoid disk spinup, when in an appropriate
|
||||
|
|
|
@ -1154,7 +1154,9 @@ _cpufreq_event_cb_powersave(void *data EINA_UNUSED, int type, void *event)
|
|||
break;
|
||||
}
|
||||
|
||||
// fallthrough is intended
|
||||
case E_POWERSAVE_MODE_EXTREME:
|
||||
default:
|
||||
if (has_powersave)
|
||||
_cpufreq_set_governor("powersave");
|
||||
break;
|
||||
|
@ -1281,6 +1283,7 @@ typedef struct _Thread_Config Thread_Config;
|
|||
struct _Thread_Config
|
||||
{
|
||||
int interval;
|
||||
E_Powersave_Sleeper *sleeper;
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -1298,9 +1301,8 @@ _cpufreq_cb_frequency_check_main(void *data, Ecore_Thread *th)
|
|||
else
|
||||
_cpufreq_status_free(status);
|
||||
if (ecore_thread_check(th)) break;
|
||||
usleep((1000000.0 / 8.0) * (double)thc->interval);
|
||||
e_powersave_sleeper_sleep(thc->sleeper, thc->interval);
|
||||
}
|
||||
free(thc);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1360,6 +1362,15 @@ _cpufreq_cb_frequency_check_notify(void *data EINA_UNUSED,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cpufreq_cb_frequency_check_done(void *data,
|
||||
Ecore_Thread *th EINA_UNUSED)
|
||||
{
|
||||
Thread_Config *thc = data;
|
||||
e_powersave_sleeper_free(thc->sleeper);
|
||||
free(thc);
|
||||
}
|
||||
|
||||
void
|
||||
_cpufreq_poll_interval_update(void)
|
||||
{
|
||||
|
@ -1374,10 +1385,13 @@ _cpufreq_poll_interval_update(void)
|
|||
if (thc)
|
||||
{
|
||||
thc->interval = cpufreq_config->poll_interval;
|
||||
thc->sleeper = e_powersave_sleeper_new();
|
||||
cpufreq_config->frequency_check_thread =
|
||||
ecore_thread_feedback_run(_cpufreq_cb_frequency_check_main,
|
||||
_cpufreq_cb_frequency_check_notify,
|
||||
NULL, NULL, thc, EINA_TRUE);
|
||||
_cpufreq_cb_frequency_check_done,
|
||||
_cpufreq_cb_frequency_check_done,
|
||||
thc, EINA_TRUE);
|
||||
}
|
||||
e_config_save_queue();
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ _temperature_thread_free(Tempthread *tth)
|
|||
#ifdef HAVE_EEZE
|
||||
EINA_LIST_FREE(tth->tempdevs, s) eina_stringshare_del(s);
|
||||
#endif
|
||||
e_powersave_sleeper_free(tth->sleeper);
|
||||
free(tth->extn);
|
||||
free(tth);
|
||||
}
|
||||
|
@ -328,7 +329,11 @@ _temperature_check_main(void *data, Ecore_Thread *th)
|
|||
temp = temperature_tempget_get(tth);
|
||||
if (ptemp != temp) ecore_thread_feedback(th, (void *)((long)temp));
|
||||
ptemp = temp;
|
||||
usleep((1000000.0 / 8.0) * (double)tth->poll_interval);
|
||||
e_powersave_sleeper_sleep(tth->sleeper, tth->poll_interval);
|
||||
if (e_powersave_mode_get() == E_POWERSAVE_MODE_FREEZE)
|
||||
usleep((1000000.0 / 800.0) * (double)tth->poll_interval);
|
||||
else
|
||||
usleep((1000000.0 / 8.0) * (double)tth->poll_interval);
|
||||
if (ecore_thread_check(th)) break;
|
||||
}
|
||||
}
|
||||
|
@ -361,6 +366,7 @@ temperature_face_update_config(Config_Face *inst)
|
|||
tth->poll_interval = inst->poll_interval;
|
||||
tth->sensor_type = inst->sensor_type;
|
||||
tth->inst = inst;
|
||||
tth->sleeper = e_powersave_sleeper_new();
|
||||
if (inst->sensor_name)
|
||||
tth->sensor_name = eina_stringshare_add(inst->sensor_name);
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ struct _Tempthread
|
|||
const char *sensor_name;
|
||||
const char *sensor_path;
|
||||
void *extn;
|
||||
E_Powersave_Sleeper *sleeper;
|
||||
#ifdef HAVE_EEZE
|
||||
Eina_List *tempdevs;
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue