Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1366328
  • 博文数量: 860
  • 博客积分: 425
  • 博客等级: 下士
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-20 19:57
个人简介

对技术执着

文章分类

全部博文(860)

文章存档

2019年(16)

2018年(12)

2015年(732)

2013年(85)

2012年(15)

我的朋友

分类: LINUX

2015-03-14 14:17:00

原文地址:wake lock机制 作者:wangbaolin719


  1. //based on linux v3.14 source code
  2. 一、概述
  3. Wake Lock是一种锁的机制, 只要有人拿着这个锁,系统就无法进入休眠,可以被用户态程序和内核获得. 这个锁可以是有超时的或者是没有超时的,超时的锁会在时间过去以后自动解锁. 如果没有锁了或者超时了, 内核就会启动休眠的那套机制来进入休眠.

  4. 二、相关结构体
  5. struct wake_lock {
  6. #ifdef CONFIG_HAS_WAKELOCK
  7.     struct list_head link;    //链入锁链表节点
  8.     int flags; //锁标志
  9.     const char *name;    //锁名字
  10.     unsigned long expires;    //超时时间
  11. #ifdef CONFIG_WAKELOCK_STAT
  12.     struct {
  13.         int count;
  14.         int expire_count;
  15.         int wakeup_count;
  16.         ktime_t total_time;
  17.         ktime_t prevent_suspend_time;
  18.         ktime_t max_time;
  19.         ktime_t last_time;
  20.     } stat;    //记录锁信息
  21. #endif
  22. #endif
  23. };

  24. 三、wakelocks初始化
  25. 1. 内核维护了两个活动锁链表,active_wake_locks[WAKE_LOCK_TYPE_COUNT]
  26. 1.1 active_wake_locks[0]维护的是suspend lock.WAKE_LOCK_SUSPEND这种锁如果被某个task持有,那么系统将无法进入休眠。
  27. 1.2 active_wake_locks[1]维护的是idle lock.WAKE_LOCK_IDLE这种锁不会影响到系统进入休眠,但是如果这种锁被持有,那么系统将无法进入idle空闲模式。
  28. 2. 内核维护了还一个非活动锁链表inactive_locks,用来记录所有处于inactive状态的锁.

  29. static int __init wakelocks_init(void)
  30. {
  31.     int ret;
  32.     int i;
  33.     
  34.     //初始化active_wake_locks数组中的两个类型锁链表: WAKE_LOCK_SUSPEND,WAKE_LOCK_IDLE
  35.     for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
  36.         INIT_LIST_HEAD(&active_wake_locks[i]);

  37.     //初始化wakelock deleted_wake_locks,同时将其加入到非活动锁链表中
  38. #ifdef CONFIG_WAKELOCK_STAT
  39.     wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,"deleted_wake_locks");
  40. #endif
  41.     
  42.     // 初始化wakelock: main, sys_sync, unknown_wakeups, 同时将其加入到非活动锁链表中
  43.     //给main_wake_lock 加锁
  44.     wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
  45.     wake_lock(&main_wake_lock);
  46.     wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
  47.     wake_lock_init(&suspend_backoff_lock, WAKE_LOCK_SUSPEND,"suspend_backoff");

  48.     //platform device 和 driver注册
  49.     ret = platform_device_register(&power_device);
  50.     if (ret) {
  51.         pr_err("wakelocks_init: platform_device_register failed\n");
  52.         goto err_platform_device_register;
  53.     }
  54.     ret = platform_driver_register(&power_driver);
  55.     if (ret) {
  56.         pr_err("wakelocks_init: platform_driver_register failed\n");
  57.         goto err_platform_driver_register;
  58.     }

  59.     //新建工作队列和工作者内核线程
  60.     INIT_COMPLETION(suspend_sys_sync_comp);
  61.     suspend_sys_sync_work_queue = create_singlethread_workqueue("suspend_sys_sync");
  62.     if (suspend_sys_sync_work_queue == NULL) {
  63.         ret = -ENOMEM;
  64.         goto err_suspend_sys_sync_work_queue;
  65.     }

  66.     suspend_work_queue = create_singlethread_workqueue("suspend");
  67.     if (suspend_work_queue == NULL) {
  68.         ret = -ENOMEM;
  69.         goto err_suspend_work_queue;
  70.     }

  71.     //创建proc接口
  72. #ifdef CONFIG_WAKELOCK_STAT
  73.     proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
  74. #endif

  75.     return 0;

  76. err_suspend_sys_sync_work_queue:
  77. err_suspend_work_queue:
  78.     platform_driver_unregister(&power_driver);
  79. err_platform_driver_register:
  80.     platform_device_unregister(&power_device);
  81. err_platform_device_register:
  82.     wake_lock_destroy(&suspend_backoff_lock);
  83.     wake_lock_destroy(&unknown_wakeup);
  84.     wake_lock_destroy(&main_wake_lock);
  85. #ifdef CONFIG_WAKELOCK_STAT
  86.     wake_lock_destroy(&deleted_wake_locks);
  87. #endif
  88.     return ret;
  89. }

  90. 四、wake lock使用
  91. 1. 初始化一个wake lock锁
  92. //该函数设置锁的名字,类型,最后将新建的锁挂接到一个专门链接这些非锁状态的链表inactive_locks上(新建的wakelock初期都是处于非锁状态的,除非显示调用函数wake_lock来上锁)
  93. void wake_lock_init(struct wake_lock *lock, int type, const char *name)
  94. {
  95.     unsigned long irqflags = 0;

  96.     if (name)
  97.         lock->name = name;
  98.     BUG_ON(!lock->name);

  99.     if (debug_mask & DEBUG_WAKE_LOCK)
  100.         pr_info("wake_lock_init name=%s\n", lock->name);
  101. #ifdef CONFIG_WAKELOCK_STAT
  102.     lock->stat.count = 0;
  103.     lock->stat.expire_count = 0;
  104.     lock->stat.wakeup_count = 0;
  105.     lock->stat.total_time = ktime_set(0, 0);
  106.     lock->stat.prevent_suspend_time = ktime_set(0, 0);
  107.     lock->stat.max_time = ktime_set(0, 0);
  108.     lock->stat.last_time = ktime_set(0, 0);
  109. #endif
  110.     lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;

  111.     INIT_LIST_HEAD(&lock->link);
  112.     spin_lock_irqsave(&list_lock, irqflags);
  113.     //将锁挂到非锁状态的链表inactive_locks上
  114.     list_add(&lock->link, &inactive_locks);
  115.     spin_unlock_irqrestore(&list_lock, irqflags);
  116. }

  117. 2. 上锁
  118. wakelock有两种形式的锁:超时锁和非超时锁,这两种形式的锁都是使用函数wake_lock_init()来初始化,只是在上锁的时候会有一点点差别,超时锁使用函数wake_lock_timeout(),而非超时锁使用函数wake_lock(), 这个两个函数会最终调用到同一个函数wake_lock_internal(),该函数依靠传入的不同参数来选择不同的路径来工作。值得注意的是,非超时锁必须手工解锁,否则系统永远不能进入睡眠。
  119. static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
  120. void wake_lock(struct wake_lock *lock)
  121. {
  122.     wake_lock_internal(lock, 0, 0);
  123. }

  124. void wake_lock_timeout(struct wake_lock *lock, long timeout)
  125. {
  126.     wake_lock_internal(lock, timeout, 1);
  127. }

  128. static void wake_lock_internal(struct wake_lock *lock, long timeout, int has_timeout)
  129. {
  130.     int type;
  131.     unsigned long irqflags;
  132.     long expire_in;

  133.     spin_lock_irqsave(&list_lock, irqflags);
  134.     //上锁前,检查锁类型和有效性,是否为WAKE_LOCK_SUSPEND或WAKE_LOCK_IDLE某一种
  135.     type = lock->flags & WAKE_LOCK_TYPE_MASK;
  136.     BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
  137.     BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
  138. #ifdef CONFIG_WAKELOCK_STAT
  139.     //检查wait_for_wakeup标志
  140.     if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
  141.         if (debug_mask & DEBUG_WAKEUP)
  142.             pr_info("wakeup wake lock: %s\n", lock->name);
  143.         wait_for_wakeup = 0;
  144.         lock->stat.wakeup_count++;
  145.     }
  146.     //检查超时锁
  147.     if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
  148.      (long)(lock->expires - jiffies) <= 0) {
  149.         wake_unlock_stat_locked(lock, 0);//若超时,则解锁
  150.         lock->stat.last_time = ktime_get();
  151.     }
  152. #endif
  153.     //上锁,设置WAKE_LOCK_ACTIVE标志
  154.     if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
  155.         lock->flags |= WAKE_LOCK_ACTIVE;
  156. #ifdef CONFIG_WAKELOCK_STAT
  157.         lock->stat.last_time = ktime_get();
  158. #endif
  159.     }
  160.     //lock从非锁状态的链表inactive_locks上删除
  161.     list_del(&lock->link);

  162.     //has_timeout=1,表示是超时锁
  163.     if (has_timeout) {
  164.         if (debug_mask & DEBUG_WAKE_LOCK)
  165.             pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",
  166.                 lock->name, type, timeout / HZ,
  167.                 (timeout % HZ) * MSEC_PER_SEC / HZ);
  168.         //设置超时时间
  169.         lock->expires = jiffies + timeout;
  170.         lock->flags |= WAKE_LOCK_AUTO_EXPIRE;//超时锁标志
  171.         //超时锁重新挂入链表尾
  172.         list_add_tail(&lock->link, &active_wake_locks[type]);
  173.     } else {
  174.         //非超时锁
  175.         if (debug_mask & DEBUG_WAKE_LOCK)
  176.             pr_info("wake_lock: %s, type %d\n", lock->name, type);
  177.         lock->expires = LONG_MAX;
  178.         lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;//非超时锁标志
  179.         //非超时锁直接挂入链表
  180.         list_add(&lock->link, &active_wake_locks[type]);
  181.     }

  182.     //对于WAKE_LOCK_SUSPEND型的锁
  183.     if (type == WAKE_LOCK_SUSPEND) {
  184.         current_event_num++;
  185. #ifdef CONFIG_WAKELOCK_STAT
  186.         if (lock == &main_wake_lock)
  187.             update_sleep_wait_stats_locked(1);
  188.         else if (!wake_lock_active(&main_wake_lock))
  189.             update_sleep_wait_stats_locked(0);
  190. #endif
  191.         if (has_timeout)
  192.             //检查所有处于活动状态的 WAKE_LOCK_SUSPEND 锁(即在 active_wake_locks 链表上的WAKE_LOCK_SUSPEND 锁,或者说当前被加锁了的 WAKE_LOCK_SUSPEND 锁),是否有超期锁已经过期,如果有则把过期超期锁从 active_wake_locks 上删除,挂到 inactive_locks 上。同时它还检查链表上有没有非超期锁,如果有则直接返回-1,否则它最终返回的是所有超期锁过期时间的最大值
  193.             expire_in = has_wake_lock_locked(type);
  194.         else
  195.             expire_in = -1;

  196.         //如果 has_wake_lock_locked 函数返回的是-1(表示当前活动锁有非超时锁)或者 0(表示所有活动锁都是超时锁,且全已经超时),则删除 expire_timer,并排队一个 suspend 工作到 suspend_work_queue 工作队列,最终系统会suspend
  197.         if (expire_in > 0) {
  198.             //有超时锁,设置超时定时器,超时调用expire_wake_locks函数
  199.             if (debug_mask & DEBUG_EXPIRE)
  200.                 pr_info("wake_lock: %s, start expire timer, ""%ld\n", lock->name, expire_in);
  201.             mod_timer(&expire_timer, jiffies + expire_in);
  202.         } else {
  203.             //无超时锁,删除超时定时器
  204.             if (del_timer(&expire_timer))
  205.                 if (debug_mask & DEBUG_EXPIRE)
  206.                     pr_info("wake_lock: %s, stop expire timer\n",lock->name);
  207.             //如果超时锁为0,且无非超时锁时,expire_in为0,启动suspend_work_queue工作队列进行suspend
  208.             //也就是说链表active_wake_locks[WAKE_LOCK_SUSPEND]为NULL,就没有锁阻止系统进入suspend了,那么系统就可以执行suspend的流程了。
  209.             if (expire_in == 0)
  210.                 queue_work(suspend_work_queue, &suspend_work);
  211.         }
  212.     }
  213.     spin_unlock_irqrestore(&list_lock, irqflags);
  214. }

  215. 3. 解锁
  216. void wake_unlock(struct wake_lock *lock)
  217. {
  218.     int type;
  219.     unsigned long irqflags;
  220.     spin_lock_irqsave(&list_lock, irqflags);
  221.     type = lock->flags & WAKE_LOCK_TYPE_MASK;
  222. #ifdef CONFIG_WAKELOCK_STAT
  223.     wake_unlock_stat_locked(lock, 0);
  224. #endif
  225.     if (debug_mask & DEBUG_WAKE_LOCK)
  226.         pr_info("wake_unlock: %s\n", lock->name);
  227.     //去锁标志
  228.     lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
  229.     //该锁从active_wake_locks[type]链表移除,加入inactive_locks链表
  230.     list_del(&lock->link);
  231.     list_add(&lock->link, &inactive_locks);

  232.     //前面已经说了只有类型为WAKE_LOCK_SUSPEND的wakelock被上锁才会阻止系统进入suspend,那么也就是说只要链表active_wake_locks[WAKE_LOCK_SUSPEND]为NULL,就没有锁阻止系统进入suspend了,那么系统就可以执行suspend的流程了。
  233.     if (type == WAKE_LOCK_SUSPEND) {
  234.         //检查所有处于活动状态的 WAKE_LOCK_SUSPEND 锁
  235.         long has_lock = has_wake_lock_locked(type);
  236.         //has_lock>0表示有超时锁,has_lock为最大超时时间,设置定时器,超时调用expire_wake_locks函数
  237.         if (has_lock > 0) {
  238.             if (debug_mask & DEBUG_EXPIRE)
  239.                 pr_info("wake_unlock: %s, start expire timer, ""%ld\n", lock->name, has_lock);
  240.             mod_timer(&expire_timer, jiffies + has_lock);
  241.         } else {
  242.             //has_lock=-1,表示有非超时锁。
  243.             if (del_timer(&expire_timer))
  244.                 if (debug_mask & DEBUG_EXPIRE)
  245.                     pr_info("wake_unlock: %s, stop expire ""timer\n", lock->name);
  246.             //如果has_lock=0,表示超时锁已超时时间为0,且无非超时锁时,启动suspend流程
  247.             if (has_lock == 0)
  248.                 queue_work(suspend_work_queue, &suspend_work);
  249.         }
  250.         if (lock == &main_wake_lock) {
  251.             if (debug_mask & DEBUG_SUSPEND)
  252.                 print_active_locks(WAKE_LOCK_SUSPEND);
  253. #ifdef CONFIG_WAKELOCK_STAT
  254.             update_sleep_wait_stats_locked(0);
  255. #endif
  256.         }
  257.     }
  258.     spin_unlock_irqrestore(&list_lock, irqflags);
  259. }

  260. 4. 设置超时锁时,设置超时定时器,超时时会回调定时器函数
  261. static void expire_wake_locks(unsigned long data)
  262. {
  263.     long has_lock;
  264.     unsigned long irqflags;
  265.     if (debug_mask & DEBUG_EXPIRE)
  266.         pr_info("expire_wake_locks: start\n");
  267.     spin_lock_irqsave(&list_lock, irqflags);
  268.     if (debug_mask & DEBUG_SUSPEND)
  269.         print_active_locks(WAKE_LOCK_SUSPEND);

  270.     //检查所有处于活动状态的 WAKE_LOCK_SUSPEND 锁
  271.     has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);
  272.     if (debug_mask & DEBUG_EXPIRE)
  273.         pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);

  274.     //如果没有SUSPEND类型的wakelock处于active,那么将调用suspend
  275.     if (has_lock == 0)
  276.         queue_work(suspend_work_queue, &suspend_work);
  277.     spin_unlock_irqrestore(&list_lock, irqflags);
  278. }

  279. static long has_wake_lock_locked(int type)
  280. {
  281.     struct wake_lock *lock, *n;
  282.     long max_timeout = 0;

  283.     BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
  284.     //遍历链表中的所有锁
  285.     list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) {
  286.         //若设置了超时锁标志
  287.         if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
  288.             //计算还剩余的时间
  289.    
阅读(451) | 评论(0) | 转发(0) |
0

上一篇:linux notifier

下一篇:wait queue机制

给主人留下些什么吧!~~