wakelock锁"/>
wakelock锁
android的内核版本中,提供了一套阻止系统进入睡眠的wakelock接口,该套接口共有6个;
- struct wake_lock{
- struct wakeup_source ws;
- };
- static inline void wake_lock_init(struct wake_lock *lock,int type,const char* name)
- {
- wakeup_source_init(&lock->ws,name);
- }
- static inline void wake_lock_destroy(struct wake_lock* lock)
- {
- wakeup_source_trash(&lock->ws);
- }
- static inline void wake_lock(struct wake_lock* lock)
- {
- __pm_stay_awake(&lock->ws);
- }
- static inline void wake_lock_timeout(struct wake_lock* lock,long timeout)
- {
- __pm_stay_awake(&lock->ws);
- }
- static inline void wake_unlock(struct wake_lock* lock)
- {
- __pm_relax(&lock->ws);
- }
- static inline bool wake_lock_active(struct wake_lock* lock)
- {
- return lock->ws.active;
- }
还有一个重要的数据结构需要亮一下,那就是wakeup_source,该数据结构完成wakelock锁的基本控制
- /**
- * struct wakeup_source - Representation of wakeup sources
- *
- * @total_time: Total time this wakeup source has been active.
- * @max_time: Maximum time this wakeup source has been continuously active.
- * @last_time: Monotonic clock when the wakeup source's was touched last time.
- * @prevent_sleep_time: Total time this source has been preventing autosleep.
- * @event_count: Number of signaled wakeup events.
- * @active_count: Number of times the wakeup sorce was activated.
- * @relax_count: Number of times the wakeup sorce was deactivated.
- * @expire_count: Number of times the wakeup source's timeout has expired.
- * @wakeup_count: Number of times the wakeup source might abort suspend.
- * @active: Status of the wakeup source.
- * @has_timeout: The wakeup source has been activated with a timeout.
- */
- struct wakeup_source {
- const char *name;
- struct list_head entry;
- spinlock_t lock;
- struct timer_list timer;
- unsigned long timer_expires;
- ktime_t total_time;
- ktime_t max_time;
- ktime_t last_time;
- ktime_t start_prevent_time;
- ktime_t prevent_sleep_time;
- unsigned long event_count;
- unsigned long active_count;
- unsigned long relax_count;
- unsigned long expire_count;
- unsigned long wakeup_count;
- bool active:1;
- bool autosleep_enabled:1;
- };
1)wake_lock_init:实现wakelock锁的初始化,包括名字初始化,添加到wakelock锁的统一控制链表wakeup_sources中;
- static inline void wake_lock_init(struct wake_lock *lock,int type,const char* name)
- {
- wakeup_source_init(&lock->ws,name);
- }
- <pre class="cpp" name="code">static inline void wakeup_source_init(struct wakeup_source *ws,
- const char *name)
- {
- wakeup_source_prepare(ws, name);
- wakeup_source_add(ws);
- }
其中wakelock_source_prepare主要完成的是锁的名字的初始化
- /**
- * wakeup_source_prepare - Prepare a new wakeup source for initialization.
- * @ws: Wakeup source to prepare.
- * @name: Pointer to the name of the new wakeup source.
- *
- * Callers must ensure that the @name string won't be freed when @ws is still in
- * use.
- */
- void wakeup_source_prepare(struct wakeup_source *ws, const char *name)
- {
- if (ws) {
- memset(ws, 0, sizeof(*ws));
- ws->name = name;
- }
- }
- EXPORT_SYMBOL_GPL(wakeup_source_prepare);
而wakeup_source_add则完成的工作比较多,包括自旋锁的初始化,添加到wakelock锁的全局控制链表中,超时timer的初始化等
- /**
- * wakeup_source_add - Add given object to the list of wakeup sources.
- * @ws: Wakeup source object to add to the list.
- */
- void wakeup_source_add(struct wakeup_source *ws)
- {
- if (WARN_ON(!ws))
- return;
- spin_lock_init(&ws->lock);
- setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);//pm_wakeup_timer_fn设置为wakelock锁的超时回调,供超时锁使用
- ws->active = false;
- ws->last_time = ktime_get();
- spin_lock_irq(&events_lock);
- list_add_rcu(&ws->entry, &wakeup_sources);//此处添加到链表中,wakelock模块主要操作该链表来控制wakelock锁
- spin_unlock_irq(&events_lock);
- }
- EXPORT_SYMBOL_GPL(wakeup_source_add);
其中pm_wakeup_timer_fn的实现如下,主要完成wakelock锁的释放,以及相关debug信息的记录
- /**
- * pm_wakeup_timer_fn - Delayed finalization of a wakeup event.
- * @data: Address of the wakeup source object associated with the event source.
- *
- * Call wakeup_source_deactivate() for the wakeup source whose address is stored
- * in @data if it is currently active and its timer has not been canceled and
- * the expiration time of the timer is not in future.
- */
- static void pm_wakeup_timer_fn(unsigned long data)
- {
- struct wakeup_source *ws = (struct wakeup_source *)data;
- unsigned long flags;
- spin_lock_irqsave(&ws->lock, flags);
- if (ws->active && ws->timer_expires
- && time_after_eq(jiffies, ws->timer_expires)) {
- wakeup_source_deactivate(ws);
- ws->expire_count++;
- }
- spin_unlock_irqrestore(&ws->lock, flags);
- }
2)wake_lock_destroy:该接口完成wakelock锁的销毁操作,其实使用上的地方不多,一般创建完一个wakelock锁都会一直使用的
- static inline void wake_lock_destroy(struct wake_lock* lock)
- {
- wakeup_source_trash(&lock->ws);
- }
- static inline void wakeup_source_trash(struct wakeup_source *ws)
- {
- wakeup_source_remove(ws);
- wakeup_source_drop(ws);
- }
其中wakeup_source_remove负责把wakelocks锁从控制链表中删除
- /**
- * wakeup_source_remove - Remove given object from the wakeup sources list.
- * @ws: Wakeup source object to remove from the list.
- */
- void wakeup_source_remove(struct wakeup_source *ws)
- {
- if (WARN_ON(!ws))
- return;
- spin_lock_irq(&events_lock);
- list_del_rcu(&ws->entry);
- spin_unlock_irq(&events_lock);
- synchronize_rcu();
- }
而wakeup_source_drop则主要负责把对应timer从激活链表中删除(如果是出于激活状态),以及释放wakelock锁,而且该函数注释也提醒了,调用该函数时,一定要确保__pm_stay_awake() or __pm_wakeup_event()两个函数没有并行被调用,否则删除状态未知。
- /**
- * wakeup_source_drop - Prepare a struct wakeup_source object for destruction.
- * @ws: Wakeup source to prepare for destruction.
- *
- * Callers must ensure that __pm_stay_awake() or __pm_wakeup_event() will never
- * be run in parallel with this function for the same wakeup source object.
- */
- void wakeup_source_drop(struct wakeup_source *ws)
- {
- if (!ws)
- return;
- del_timer_sync(&ws->timer);
- __pm_relax(ws);
- }
3)wake_lock:投票反对睡眠(待完善)
- static inline void wake_lock(struct wake_lock* lock)
- {
- __pm_stay_awake(&lock->ws);
- }
__pm_stay_awake完成相关超时timer的删除,相关debug信息更新,以及持锁信息的+1操作
- void __pm_stay_awake(struct wakeup_source *ws)
- {
- unsigned long flags;
- if (!ws)
- return;
- spin_lock_irqsave(&ws->lock, flags);
- wakeup_source_report_event(ws);
- del_timer(&ws->timer);
- ws->timer_expires = 0;
- spin_unlock_irqrestore(&ws->lock, flags);
- }
- static void wakeup_source_report_event(struct wakeup_source *ws)
- {
- ws->event_count++;
- /* This is racy, but the counter is approximate anyway. */
- if (events_check_enabled)
- ws->wakeup_count++;
- if (!ws->active)
- wakeup_source_activate(ws);
- }
- static void wakeup_source_activate(struct wakeup_source *ws)
- {
- unsigned int cec;
- ws->active = true;
- ws->active_count++;
- ws->last_time = ktime_get();
- if (ws->autosleep_enabled)
- ws->start_prevent_time = ws->last_time;
- /* Increment the counter of events in progress. */
- cec = atomic_inc_return(&combined_event_count);
- trace_wakeup_source_activate(ws->name, cec);
- }
4)wake_lock_timeout:投超时锁,超时后释放锁
- static inline void wake_lock_timeout(struct wake_lock* lock,long timeout)
- {
- __pm_wakeup_event(&lock->ws,jiffies_to_msecs(timeout));
- }
- void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec)
- {
- unsigned long flags;
- unsigned long expires;
- if (!ws)
- return;
- spin_lock_irqsave(&ws->lock, flags);
- wakeup_source_report_event(ws);//先上锁
- if (!msec) {//如果超时时间为0,则立刻释放锁
- wakeup_source_deactivate(ws);
- goto unlock;
- }
- expires = jiffies + msecs_to_jiffies(msec);
- if (!expires)
- expires = 1;
- if (!ws->timer_expires || time_after(expires, ws->timer_expires)) {
- mod_timer(&ws->timer, expires);//更新timer超时时间,超时后调用 pm_wakeup_timer_fn释放锁
- ws->timer_expires = expires;
- }
- unlock:
- spin_unlock_irqrestore(&ws->lock, flags);
- }
5)wake_unlock:投票同意睡眠,释放wakelock锁
- static inline void wake_unlock(struct wake_lock* lock)
- {
- __pm_relax(&lock->ws);
- }
- void __pm_relax(struct wakeup_source *ws)
- {
- unsigned long flags;
- if (!ws)
- return;
- spin_lock_irqsave(&ws->lock, flags);
- if (ws->active)
- wakeup_source_deactivate(ws);//释放锁
- spin_unlock_irqrestore(&ws->lock, flags);
- }
- static void wakeup_source_deactivate(struct wakeup_source *ws)
- {
- unsigned int cnt, inpr, cec;
- ktime_t duration;
- ktime_t now;
- ws->relax_count++;
- /*
- * __pm_relax() may be called directly or from a timer function.
- * If it is called directly right after the timer function has been
- * started, but before the timer function calls __pm_relax(), it is
- * possible that __pm_stay_awake() will be called in the meantime and
- * will set ws->active. Then, ws->active may be cleared immediately
- * by the __pm_relax() called from the timer function, but in such a
- * case ws->relax_count will be different from ws->active_count.
- */
- if (ws->relax_count != ws->active_count) {
- ws->relax_count--;
- return;
- }
- ws->active = false;
- now = ktime_get();
- duration = ktime_sub(now, ws->last_time);
- ws->total_time = ktime_add(ws->total_time, duration);
- if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))
- ws->max_time = duration;
- ws->last_time = now;
- del_timer(&ws->timer);
- ws->timer_expires = 0;
- if (ws->autosleep_enabled)
- update_prevent_sleep_time(ws, now);
- /*
- * Increment the counter of registered wakeup events and decrement the
- * couter of wakeup events in progress simultaneously.
- */
- cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count);
- trace_wakeup_source_deactivate(ws->name, cec);
- split_counters(&cnt, &inpr);
- if (!inpr && waitqueue_active(&wakeup_count_wait_queue))//如果满足睡眠条件,则唤醒等待队列
- wake_up(&wakeup_count_wait_queue);//此处需要配合前边讲的autosleep来看了}
6)wake_lock_active:返回锁的激活状态,主要是查询功能
- static inline bool wake_lock_active(struct wake_lock* lock)
- {
- return lock->ws.active;
- }
更多推荐
wakelock锁
发布评论