Evdev auto wakelock 介绍
介绍kernel-2.6.25 关于event 加锁的机制,从中窥探linux的锁机制。
kernel版本比较旧,对比2.6.32发现kernel在锁机制方面基本没变,但是在机制的实现上有很大的变化。
1.evdev模块初始化
module_init(evdev_init);
2.evdev初始化
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
3.回调方法集定义
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
4.event方法的实现函数
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
//...
rcu_read_lock();
//...
if (client)
evdev_pass_event(client, &event);
else
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event);
//...
rcu_read_unlock();
//...
}
5.event发生时的处理,加锁了!获取evdev的超时锁,超时时间是5*HZ,HZ根据不同CPU而定,这里是50ms
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
//...
#ifdef CONFIG_ANDROID_POWER
android_lock_suspend_auto_expire(&client->suspend_lock, 5 * HZ); //50ms
#endif
//...
}
6.evdev节点打开方法的实现,初始化名为“evdev”的锁,锁的类型不在这里声明,在申请锁的时候才声明是超时锁还是非超时锁
static int evdev_open(struct inode *inode, struct file *file)
{
//...
#ifdef CONFIG_ANDROID_POWER
client->suspend_lock.name = "evdev";
android_init_suspend_lock(&client->suspend_lock);
#endif
//...
}
static int evdev_release(struct inode *inode, struct file *file)
{
//...
#ifdef CONFIG_ANDROID_POWER
android_uninit_suspend_lock(&client->suspend_lock);
#endif
//...
}
7.申请超时锁的实现,把锁加入活跃数组。共有三种数组,这里是之一。
void android_lock_suspend_auto_expire(android_suspend_lock_t *lock, int timeout) { unsigned long irqflags; spin_lock_irqsave(&g_list_lock, irqflags); #ifdef CONFIG_ANDROID_POWER_STAT if(!(lock->flags & ANDROID_SUSPEND_LOCK_ACTIVE)) { lock->flags |= ANDROID_SUSPEND_LOCK_ACTIVE; lock->stat.last_time = ktime_get(); } #endif if (android_power_debug_mask & ANDROID_POWER_DEBUG_WAKE_LOCK) printk(KERN_INFO "android_power: acquire wake lock: %s, " "timeout %d.%03lu\n", lock->name, timeout / HZ, (timeout % HZ) * MSEC_PER_SEC / HZ); lock->expires = jiffies + timeout; lock->flags |= ANDROID_SUSPEND_LOCK_AUTO_EXPIRE; list_del(&lock->link); list_add(&lock->link, &g_active_partial_wake_locks); g_current_event_num++; wake_up(&g_wait_queue); spin_unlock_irqrestore(&g_list_lock, irqflags); }