Skip to content
This repository has been archived by the owner on Sep 18, 2022. It is now read-only.

Commit

Permalink
PM / Sleep: User space wakeup sources garbage collector Kconfig option
Browse files Browse the repository at this point in the history
Make it possible to configure out the user space wakeup sources
garbage collector for debugging and default Android builds.

Change-Id: I85ca6caa92c8e82d863f0fa58d8861b5571c1b4a
Signed-off-by: Rafael J. Wysocki <[email protected]>
Acked-by: Arve Hjønnevåg <[email protected]>
Git-commit: 4e585d2
Git-repo: git://codeaurora.org/kernel/msm.git
Signed-off-by: Anurag Singh <[email protected]>
  • Loading branch information
rjwysocki authored and Anurag Singh committed Mar 13, 2013
1 parent 902df69 commit 90cc51f
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 39 deletions.
5 changes: 5 additions & 0 deletions kernel/power/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ config PM_WAKELOCKS_LIMIT
default 100
depends on PM_WAKELOCKS

config PM_WAKELOCKS_GC
bool "Garbage collector for user space wakeup sources"
depends on PM_WAKELOCKS
default y

config PM_RUNTIME
bool "Run-time PM core functionality"
depends on !IA64_HP_SIM
Expand Down
101 changes: 62 additions & 39 deletions kernel/power/wakelock.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,18 @@
#include <linux/rbtree.h>
#include <linux/slab.h>

#define WL_GC_COUNT_MAX 100
#define WL_GC_TIME_SEC 300

static DEFINE_MUTEX(wakelocks_lock);

struct wakelock {
char *name;
struct rb_node node;
struct wakeup_source ws;
#ifdef CONFIG_PM_WAKELOCKS_GC
struct list_head lru;
#endif
};

static struct rb_root wakelocks_tree = RB_ROOT;
static LIST_HEAD(wakelocks_lru_list);
static unsigned int wakelocks_gc_count;

ssize_t pm_show_wakelocks(char *buf, bool show_active)
{
Expand Down Expand Up @@ -79,6 +76,61 @@ static inline void increment_wakelocks_number(void) {}
static inline void decrement_wakelocks_number(void) {}
#endif /* CONFIG_PM_WAKELOCKS_LIMIT */

#ifdef CONFIG_PM_WAKELOCKS_GC
#define WL_GC_COUNT_MAX 100
#define WL_GC_TIME_SEC 300

static LIST_HEAD(wakelocks_lru_list);
static unsigned int wakelocks_gc_count;

static inline void wakelocks_lru_add(struct wakelock *wl)
{
list_add(&wl->lru, &wakelocks_lru_list);
}

static inline void wakelocks_lru_most_recent(struct wakelock *wl)
{
list_move(&wl->lru, &wakelocks_lru_list);
}

static void wakelocks_gc(void)
{
struct wakelock *wl, *aux;
ktime_t now;

if (++wakelocks_gc_count <= WL_GC_COUNT_MAX)
return;

now = ktime_get();
list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
u64 idle_time_ns;
bool active;

spin_lock_irq(&wl->ws.lock);
idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time));
active = wl->ws.active;
spin_unlock_irq(&wl->ws.lock);

if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC))
break;

if (!active) {
wakeup_source_remove(&wl->ws);
rb_erase(&wl->node, &wakelocks_tree);
list_del(&wl->lru);
kfree(wl->name);
kfree(wl);
decrement_wakelocks_number();
}
}
wakelocks_gc_count = 0;
}
#else /* !CONFIG_PM_WAKELOCKS_GC */
static inline void wakelocks_lru_add(struct wakelock *wl) {}
static inline void wakelocks_lru_most_recent(struct wakelock *wl) {}
static inline void wakelocks_gc(void) {}
#endif /* !CONFIG_PM_WAKELOCKS_GC */

static struct wakelock *wakelock_lookup_add(const char *name, size_t len,
bool add_if_not_found)
{
Expand Down Expand Up @@ -123,7 +175,7 @@ static struct wakelock *wakelock_lookup_add(const char *name, size_t len,
wakeup_source_add(&wl->ws);
rb_link_node(&wl->node, parent, node);
rb_insert_color(&wl->node, &wakelocks_tree);
list_add(&wl->lru, &wakelocks_lru_list);
wakelocks_lru_add(wl);
increment_wakelocks_number();
return wl;
}
Expand Down Expand Up @@ -166,42 +218,13 @@ int pm_wake_lock(const char *buf)
__pm_stay_awake(&wl->ws);
}

list_move(&wl->lru, &wakelocks_lru_list);
wakelocks_lru_most_recent(wl);

out:
mutex_unlock(&wakelocks_lock);
return ret;
}

static void wakelocks_gc(void)
{
struct wakelock *wl, *aux;
ktime_t now = ktime_get();

list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
u64 idle_time_ns;
bool active;

spin_lock_irq(&wl->ws.lock);
idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time));
active = wl->ws.active;
spin_unlock_irq(&wl->ws.lock);

if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC))
break;

if (!active) {
wakeup_source_remove(&wl->ws);
rb_erase(&wl->node, &wakelocks_tree);
list_del(&wl->lru);
kfree(wl->name);
kfree(wl);
decrement_wakelocks_number();
}
}
wakelocks_gc_count = 0;
}

int pm_wake_unlock(const char *buf)
{
struct wakelock *wl;
Expand All @@ -226,9 +249,9 @@ int pm_wake_unlock(const char *buf)
goto out;
}
__pm_relax(&wl->ws);
list_move(&wl->lru, &wakelocks_lru_list);
if (++wakelocks_gc_count > WL_GC_COUNT_MAX)
wakelocks_gc();

wakelocks_lru_most_recent(wl);
wakelocks_gc();

out:
mutex_unlock(&wakelocks_lock);
Expand Down

0 comments on commit 90cc51f

Please sign in to comment.